Home | History | Annotate | Download | only in intltest
      1 //  2017 and later: Unicode, Inc. and others.
      2 // License & terms of use: http://www.unicode.org/copyright.html
      3 
      4 #include "unicode/utypes.h"
      5 
      6 #if !UCONFIG_NO_FORMATTING
      7 
      8 #include "putilimp.h"
      9 #include "numbertest.h"
     10 
     11 static const char16_t *EXAMPLE_STRINGS[] = {
     12         u"",
     13         u"xyz",
     14         u"The quick brown fox jumps over the lazy dog",
     15         u"",
     16         u"mixed  and ASCII",
     17         u"with combining characters like ",
     18         u"A very very very very very very very very very very long string to force heap"};
     19 
     20 void NumberStringBuilderTest::runIndexedTest(int32_t index, UBool exec, const char *&name, char *) {
     21     if (exec) {
     22         logln("TestSuite NumberStringBuilderTest: ");
     23     }
     24     TESTCASE_AUTO_BEGIN;
     25         TESTCASE_AUTO(testInsertAppendUnicodeString);
     26         TESTCASE_AUTO(testSplice);
     27         TESTCASE_AUTO(testInsertAppendCodePoint);
     28         TESTCASE_AUTO(testCopy);
     29         TESTCASE_AUTO(testFields);
     30         TESTCASE_AUTO(testUnlimitedCapacity);
     31         TESTCASE_AUTO(testCodePoints);
     32     TESTCASE_AUTO_END;
     33 }
     34 
     35 void NumberStringBuilderTest::testInsertAppendUnicodeString() {
     36     UErrorCode status = U_ZERO_ERROR;
     37     UnicodeString sb1;
     38     NumberStringBuilder sb2;
     39     for (const char16_t* strPtr : EXAMPLE_STRINGS) {
     40         UnicodeString str(strPtr);
     41 
     42         NumberStringBuilder sb3;
     43         sb1.append(str);
     44         // Note: UNUM_FIELD_COUNT is like passing null in Java
     45         sb2.append(str, UNUM_FIELD_COUNT, status);
     46         assertSuccess("Appending to sb2", status);
     47         sb3.append(str, UNUM_FIELD_COUNT, status);
     48         assertSuccess("Appending to sb3", status);
     49         assertEqualsImpl(sb1, sb2);
     50         assertEqualsImpl(str, sb3);
     51 
     52         UnicodeString sb4;
     53         NumberStringBuilder sb5;
     54         sb4.append(u"");
     55         sb4.append(str);
     56         sb4.append(u"xx");
     57         sb5.append(u"xx", UNUM_FIELD_COUNT, status);
     58         assertSuccess("Appending to sb5", status);
     59         sb5.insert(2, str, UNUM_FIELD_COUNT, status);
     60         assertSuccess("Inserting into sb5", status);
     61         assertEqualsImpl(sb4, sb5);
     62 
     63         int start = uprv_min(1, str.length());
     64         int end = uprv_min(10, str.length());
     65         sb4.insert(3, str, start, end - start); // UnicodeString uses length instead of end index
     66         sb5.insert(3, str, start, end, UNUM_FIELD_COUNT, status);
     67         assertSuccess("Inserting into sb5 again", status);
     68         assertEqualsImpl(sb4, sb5);
     69 
     70         UnicodeString sb4cp(sb4);
     71         NumberStringBuilder sb5cp(sb5);
     72         sb4.append(sb4cp);
     73         sb5.append(sb5cp, status);
     74         assertSuccess("Appending again to sb5", status);
     75         assertEqualsImpl(sb4, sb5);
     76     }
     77 }
     78 
     79 void NumberStringBuilderTest::testSplice() {
     80     static const struct TestCase {
     81         const char16_t* input;
     82         const int32_t startThis;
     83         const int32_t endThis;
     84     } cases[] = {
     85             { u"", 0, 0 },
     86             { u"abc", 0, 0 },
     87             { u"abc", 1, 1 },
     88             { u"abc", 1, 2 },
     89             { u"abc", 0, 2 },
     90             { u"abc", 0, 3 },
     91             { u"lorem ipsum dolor sit amet", 8, 8 },
     92             { u"lorem ipsum dolor sit amet", 8, 11 }, // 3 chars, equal to replacement "xyz"
     93             { u"lorem ipsum dolor sit amet", 8, 18 } }; // 10 chars, larger than several replacements
     94 
     95     UErrorCode status = U_ZERO_ERROR;
     96     UnicodeString sb1;
     97     NumberStringBuilder sb2;
     98     for (auto cas : cases) {
     99         for (const char16_t* replacementPtr : EXAMPLE_STRINGS) {
    100             UnicodeString replacement(replacementPtr);
    101 
    102             // Test replacement with full string
    103             sb1.remove();
    104             sb1.append(cas.input);
    105             sb1.replace(cas.startThis, cas.endThis - cas.startThis, replacement);
    106             sb2.clear();
    107             sb2.append(cas.input, UNUM_FIELD_COUNT, status);
    108             sb2.splice(cas.startThis, cas.endThis, replacement, 0, replacement.length(), UNUM_FIELD_COUNT, status);
    109             assertSuccess("Splicing into sb2 first time", status);
    110             assertEqualsImpl(sb1, sb2);
    111 
    112             // Test replacement with partial string
    113             if (replacement.length() <= 2) {
    114                 continue;
    115             }
    116             sb1.remove();
    117             sb1.append(cas.input);
    118             sb1.replace(cas.startThis, cas.endThis - cas.startThis, UnicodeString(replacement, 1, 2));
    119             sb2.clear();
    120             sb2.append(cas.input, UNUM_FIELD_COUNT, status);
    121             sb2.splice(cas.startThis, cas.endThis, replacement, 1, 3, UNUM_FIELD_COUNT, status);
    122             assertSuccess("Splicing into sb2 second time", status);
    123             assertEqualsImpl(sb1, sb2);
    124         }
    125     }
    126 }
    127 
    128 void NumberStringBuilderTest::testInsertAppendCodePoint() {
    129     static const UChar32 cases[] = {
    130             0, 1, 60, 127, 128, 0x7fff, 0x8000, 0xffff, 0x10000, 0x1f000, 0x10ffff};
    131     UErrorCode status = U_ZERO_ERROR;
    132     UnicodeString sb1;
    133     NumberStringBuilder sb2;
    134     for (UChar32 cas : cases) {
    135         NumberStringBuilder sb3;
    136         sb1.append(cas);
    137         sb2.appendCodePoint(cas, UNUM_FIELD_COUNT, status);
    138         assertSuccess("Appending to sb2", status);
    139         sb3.appendCodePoint(cas, UNUM_FIELD_COUNT, status);
    140         assertSuccess("Appending to sb3", status);
    141         assertEqualsImpl(sb1, sb2);
    142         assertEquals("Length of sb3", U16_LENGTH(cas), sb3.length());
    143         assertEquals("Code point count of sb3", 1, sb3.codePointCount());
    144         assertEquals(
    145                 "First code unit in sb3",
    146                 !U_IS_SUPPLEMENTARY(cas) ? (char16_t) cas : U16_LEAD(cas),
    147                 sb3.charAt(0));
    148 
    149         UnicodeString sb4;
    150         NumberStringBuilder sb5;
    151         sb4.append(u"xx");
    152         sb4.insert(2, cas);
    153         sb5.append(u"xx", UNUM_FIELD_COUNT, status);
    154         assertSuccess("Appending to sb5", status);
    155         sb5.insertCodePoint(2, cas, UNUM_FIELD_COUNT, status);
    156         assertSuccess("Inserting into sb5", status);
    157         assertEqualsImpl(sb4, sb5);
    158     }
    159 }
    160 
    161 void NumberStringBuilderTest::testCopy() {
    162     UErrorCode status = U_ZERO_ERROR;
    163     for (UnicodeString str : EXAMPLE_STRINGS) {
    164         NumberStringBuilder sb1;
    165         sb1.append(str, UNUM_FIELD_COUNT, status);
    166         assertSuccess("Appending to sb1 first time", status);
    167         NumberStringBuilder sb2(sb1);
    168         assertTrue("Content should equal itself", sb1.contentEquals(sb2));
    169 
    170         sb1.append("12345", UNUM_FIELD_COUNT, status);
    171         assertSuccess("Appending to sb1 second time", status);
    172         assertFalse("Content should no longer equal itself", sb1.contentEquals(sb2));
    173     }
    174 }
    175 
    176 void NumberStringBuilderTest::testFields() {
    177     UErrorCode status = U_ZERO_ERROR;
    178     // Note: This is a C++11 for loop that calls the UnicodeString constructor on each iteration.
    179     for (UnicodeString str : EXAMPLE_STRINGS) {
    180         NumberStringBuilder sb;
    181         sb.append(str, UNUM_FIELD_COUNT, status);
    182         assertSuccess("Appending to sb", status);
    183         sb.append(str, UNUM_CURRENCY_FIELD, status);
    184         assertSuccess("Appending to sb", status);
    185         assertEquals("Reference string copied twice", str.length() * 2, sb.length());
    186         for (int32_t i = 0; i < str.length(); i++) {
    187             assertEquals("Null field first", UNUM_FIELD_COUNT, sb.fieldAt(i));
    188             assertEquals("Currency field second", UNUM_CURRENCY_FIELD, sb.fieldAt(i + str.length()));
    189         }
    190 
    191         // Very basic FieldPosition test. More robust tests happen in NumberFormatTest.
    192         // Let NumberFormatTest also take care of FieldPositionIterator material.
    193         FieldPosition fp(UNUM_CURRENCY_FIELD);
    194         sb.nextFieldPosition(fp, status);
    195         assertSuccess("Populating the FieldPosition", status);
    196         assertEquals("Currency start position", str.length(), fp.getBeginIndex());
    197         assertEquals("Currency end position", str.length() * 2, fp.getEndIndex());
    198 
    199         if (str.length() > 0) {
    200             sb.insertCodePoint(2, 100, UNUM_INTEGER_FIELD, status);
    201             assertSuccess("Inserting code point into sb", status);
    202             assertEquals("New length", str.length() * 2 + 1, sb.length());
    203             assertEquals("Integer field", UNUM_INTEGER_FIELD, sb.fieldAt(2));
    204         }
    205 
    206         NumberStringBuilder old(sb);
    207         sb.append(old, status);
    208         assertSuccess("Appending to myself", status);
    209         int32_t numNull = 0;
    210         int32_t numCurr = 0;
    211         int32_t numInt = 0;
    212         for (int32_t i = 0; i < sb.length(); i++) {
    213             UNumberFormatFields field = sb.fieldAt(i);
    214             assertEquals("Field should equal location in old", old.fieldAt(i % old.length()), field);
    215             if (field == UNUM_FIELD_COUNT) {
    216                 numNull++;
    217             } else if (field == UNUM_CURRENCY_FIELD) {
    218                 numCurr++;
    219             } else if (field == UNUM_INTEGER_FIELD) {
    220                 numInt++;
    221             } else {
    222                 errln("Encountered unknown field");
    223             }
    224         }
    225         assertEquals("Number of null fields", str.length() * 2, numNull);
    226         assertEquals("Number of currency fields", numNull, numCurr);
    227         assertEquals("Number of integer fields", str.length() > 0 ? 2 : 0, numInt);
    228     }
    229 }
    230 
    231 void NumberStringBuilderTest::testUnlimitedCapacity() {
    232     UErrorCode status = U_ZERO_ERROR;
    233     NumberStringBuilder builder;
    234     // The builder should never fail upon repeated appends.
    235     for (int i = 0; i < 1000; i++) {
    236         UnicodeString message("Iteration #");
    237         message += Int64ToUnicodeString(i);
    238         assertEquals(message, builder.length(), i);
    239         builder.appendCodePoint(u'x', UNUM_FIELD_COUNT, status);
    240         assertSuccess(message, status);
    241         assertEquals(message, builder.length(), i + 1);
    242     }
    243 }
    244 
    245 void NumberStringBuilderTest::testCodePoints() {
    246     UErrorCode status = U_ZERO_ERROR;
    247     NumberStringBuilder nsb;
    248     assertEquals("First is -1 on empty string", -1, nsb.getFirstCodePoint());
    249     assertEquals("Last is -1 on empty string", -1, nsb.getLastCodePoint());
    250     assertEquals("Length is 0 on empty string", 0, nsb.codePointCount());
    251 
    252     nsb.append(u"q", UNUM_FIELD_COUNT, status);
    253     assertSuccess("Spot 1", status);
    254     assertEquals("First is q", u'q', nsb.getFirstCodePoint());
    255     assertEquals("Last is q", u'q', nsb.getLastCodePoint());
    256     assertEquals("0th is q", u'q', nsb.codePointAt(0));
    257     assertEquals("Before 1st is q", u'q', nsb.codePointBefore(1));
    258     assertEquals("Code point count is 1", 1, nsb.codePointCount());
    259 
    260     //  is two char16s
    261     nsb.append(u"", UNUM_FIELD_COUNT, status);
    262     assertSuccess("Spot 2" ,status);
    263     assertEquals("First is still q", u'q', nsb.getFirstCodePoint());
    264     assertEquals("Last is space ship", 128640, nsb.getLastCodePoint());
    265     assertEquals("1st is space ship", 128640, nsb.codePointAt(1));
    266     assertEquals("Before 1st is q", u'q', nsb.codePointBefore(1));
    267     assertEquals("Before 3rd is space ship", 128640, nsb.codePointBefore(3));
    268     assertEquals("Code point count is 2", 2, nsb.codePointCount());
    269 }
    270 
    271 void NumberStringBuilderTest::assertEqualsImpl(const UnicodeString &a, const NumberStringBuilder &b) {
    272     // TODO: Why won't this compile without the IntlTest:: qualifier?
    273     IntlTest::assertEquals("Lengths should be the same", a.length(), b.length());
    274     IntlTest::assertEquals("Code point counts should be the same", a.countChar32(), b.codePointCount());
    275 
    276     if (a.length() != b.length()) {
    277         return;
    278     }
    279 
    280     for (int32_t i = 0; i < a.length(); i++) {
    281         IntlTest::assertEquals(
    282                 UnicodeString(u"Char at position ") + Int64ToUnicodeString(i) +
    283                 UnicodeString(u" in \"") + a + UnicodeString("\" versus \"") +
    284                 b.toUnicodeString() + UnicodeString("\""), a.charAt(i), b.charAt(i));
    285     }
    286 }
    287 
    288 #endif /* #if !UCONFIG_NO_FORMATTING */
    289