12e5b6d6dSopenharmony_ci// © 2016 and later: Unicode, Inc. and others.
22e5b6d6dSopenharmony_ci// License & terms of use: http://www.unicode.org/copyright.html
32e5b6d6dSopenharmony_ci/*
42e5b6d6dSopenharmony_ci**********************************************************************
52e5b6d6dSopenharmony_ci*   Copyright (C) 2001-2009, International Business Machines
62e5b6d6dSopenharmony_ci*   Corporation and others.  All Rights Reserved.
72e5b6d6dSopenharmony_ci**********************************************************************
82e5b6d6dSopenharmony_ci*   Date        Name        Description
92e5b6d6dSopenharmony_ci*   05/23/00    aliu        Creation.
102e5b6d6dSopenharmony_ci**********************************************************************
112e5b6d6dSopenharmony_ci*/
122e5b6d6dSopenharmony_ci
132e5b6d6dSopenharmony_ci#include <algorithm>
142e5b6d6dSopenharmony_ci#include <vector>
152e5b6d6dSopenharmony_ci#include "unicode/utypes.h"
162e5b6d6dSopenharmony_ci#include "unicode/edits.h"
172e5b6d6dSopenharmony_ci#include "unicode/unistr.h"
182e5b6d6dSopenharmony_ci#include "unicode/utf16.h"
192e5b6d6dSopenharmony_ci#include "cmemory.h"
202e5b6d6dSopenharmony_ci#include "testutil.h"
212e5b6d6dSopenharmony_ci#include "intltest.h"
222e5b6d6dSopenharmony_ci
232e5b6d6dSopenharmony_cistatic const UChar HEX[] = u"0123456789ABCDEF";
242e5b6d6dSopenharmony_ci
252e5b6d6dSopenharmony_ciUnicodeString &TestUtility::appendHex(UnicodeString &buf, UChar32 ch) {
262e5b6d6dSopenharmony_ci    if (ch >= 0x10000) {
272e5b6d6dSopenharmony_ci        if (ch >= 0x100000) {
282e5b6d6dSopenharmony_ci            buf.append(HEX[0xF&(ch>>20)]);
292e5b6d6dSopenharmony_ci        }
302e5b6d6dSopenharmony_ci        buf.append(HEX[0xF&(ch>>16)]);
312e5b6d6dSopenharmony_ci    }
322e5b6d6dSopenharmony_ci    buf.append(HEX[0xF&(ch>>12)]);
332e5b6d6dSopenharmony_ci    buf.append(HEX[0xF&(ch>>8)]);
342e5b6d6dSopenharmony_ci    buf.append(HEX[0xF&(ch>>4)]);
352e5b6d6dSopenharmony_ci    buf.append(HEX[0xF&ch]);
362e5b6d6dSopenharmony_ci    return buf;
372e5b6d6dSopenharmony_ci}
382e5b6d6dSopenharmony_ci
392e5b6d6dSopenharmony_ciUnicodeString TestUtility::hex(UChar32 ch) {
402e5b6d6dSopenharmony_ci    UnicodeString buf;
412e5b6d6dSopenharmony_ci    appendHex(buf, ch);
422e5b6d6dSopenharmony_ci    return buf;
432e5b6d6dSopenharmony_ci}
442e5b6d6dSopenharmony_ci
452e5b6d6dSopenharmony_ciUnicodeString TestUtility::hex(const UnicodeString& s) {
462e5b6d6dSopenharmony_ci    return hex(s, u',');
472e5b6d6dSopenharmony_ci}
482e5b6d6dSopenharmony_ci
492e5b6d6dSopenharmony_ciUnicodeString TestUtility::hex(const UnicodeString& s, UChar sep) {
502e5b6d6dSopenharmony_ci    UnicodeString result;
512e5b6d6dSopenharmony_ci    if (s.isEmpty()) return result;
522e5b6d6dSopenharmony_ci    UChar32 c;
532e5b6d6dSopenharmony_ci    for (int32_t i = 0; i < s.length(); i += U16_LENGTH(c)) {
542e5b6d6dSopenharmony_ci        c = s.char32At(i);
552e5b6d6dSopenharmony_ci        if (i > 0) {
562e5b6d6dSopenharmony_ci            result.append(sep);
572e5b6d6dSopenharmony_ci        }
582e5b6d6dSopenharmony_ci        appendHex(result, c);
592e5b6d6dSopenharmony_ci    }
602e5b6d6dSopenharmony_ci    return result;
612e5b6d6dSopenharmony_ci}
622e5b6d6dSopenharmony_ci
632e5b6d6dSopenharmony_ciUnicodeString TestUtility::hex(const uint8_t* bytes, int32_t len) {
642e5b6d6dSopenharmony_ci    UnicodeString buf;
652e5b6d6dSopenharmony_ci    for (int32_t i = 0; i < len; ++i) {
662e5b6d6dSopenharmony_ci        buf.append(HEX[0x0F & (bytes[i] >> 4)]);
672e5b6d6dSopenharmony_ci        buf.append(HEX[0x0F & bytes[i]]);
682e5b6d6dSopenharmony_ci    }
692e5b6d6dSopenharmony_ci    return buf;
702e5b6d6dSopenharmony_ci}
712e5b6d6dSopenharmony_ci
722e5b6d6dSopenharmony_cinamespace {
732e5b6d6dSopenharmony_ci
742e5b6d6dSopenharmony_ciUnicodeString printOneEdit(const Edits::Iterator &ei) {
752e5b6d6dSopenharmony_ci    if (ei.hasChange()) {
762e5b6d6dSopenharmony_ci        return UnicodeString() + ei.oldLength() + u"->" + ei.newLength();
772e5b6d6dSopenharmony_ci    } else {
782e5b6d6dSopenharmony_ci        return UnicodeString() + ei.oldLength() + u"=" + ei.newLength();
792e5b6d6dSopenharmony_ci    }
802e5b6d6dSopenharmony_ci}
812e5b6d6dSopenharmony_ci
822e5b6d6dSopenharmony_ci/**
832e5b6d6dSopenharmony_ci * Maps indexes according to the expected edits.
842e5b6d6dSopenharmony_ci * A destination index can occur multiple times when there are source deletions.
852e5b6d6dSopenharmony_ci * Map according to the last occurrence, normally in a non-empty destination span.
862e5b6d6dSopenharmony_ci * Simplest is to search from the back.
872e5b6d6dSopenharmony_ci */
882e5b6d6dSopenharmony_ciint32_t srcIndexFromDest(const EditChange expected[], int32_t expLength,
892e5b6d6dSopenharmony_ci                         int32_t srcLength, int32_t destLength, int32_t index) {
902e5b6d6dSopenharmony_ci    int32_t srcIndex = srcLength;
912e5b6d6dSopenharmony_ci    int32_t destIndex = destLength;
922e5b6d6dSopenharmony_ci    int32_t i = expLength;
932e5b6d6dSopenharmony_ci    while (index < destIndex && i > 0) {
942e5b6d6dSopenharmony_ci        --i;
952e5b6d6dSopenharmony_ci        int32_t prevSrcIndex = srcIndex - expected[i].oldLength;
962e5b6d6dSopenharmony_ci        int32_t prevDestIndex = destIndex - expected[i].newLength;
972e5b6d6dSopenharmony_ci        if (index == prevDestIndex) {
982e5b6d6dSopenharmony_ci            return prevSrcIndex;
992e5b6d6dSopenharmony_ci        } else if (index > prevDestIndex) {
1002e5b6d6dSopenharmony_ci            if (expected[i].change) {
1012e5b6d6dSopenharmony_ci                // In a change span, map to its end.
1022e5b6d6dSopenharmony_ci                return srcIndex;
1032e5b6d6dSopenharmony_ci            } else {
1042e5b6d6dSopenharmony_ci                // In an unchanged span, offset within it.
1052e5b6d6dSopenharmony_ci                return prevSrcIndex + (index - prevDestIndex);
1062e5b6d6dSopenharmony_ci            }
1072e5b6d6dSopenharmony_ci        }
1082e5b6d6dSopenharmony_ci        srcIndex = prevSrcIndex;
1092e5b6d6dSopenharmony_ci        destIndex = prevDestIndex;
1102e5b6d6dSopenharmony_ci    }
1112e5b6d6dSopenharmony_ci    // index is outside the string.
1122e5b6d6dSopenharmony_ci    return srcIndex;
1132e5b6d6dSopenharmony_ci}
1142e5b6d6dSopenharmony_ci
1152e5b6d6dSopenharmony_ciint32_t destIndexFromSrc(const EditChange expected[], int32_t expLength,
1162e5b6d6dSopenharmony_ci                         int32_t srcLength, int32_t destLength, int32_t index) {
1172e5b6d6dSopenharmony_ci    int32_t srcIndex = srcLength;
1182e5b6d6dSopenharmony_ci    int32_t destIndex = destLength;
1192e5b6d6dSopenharmony_ci    int32_t i = expLength;
1202e5b6d6dSopenharmony_ci    while (index < srcIndex && i > 0) {
1212e5b6d6dSopenharmony_ci        --i;
1222e5b6d6dSopenharmony_ci        int32_t prevSrcIndex = srcIndex - expected[i].oldLength;
1232e5b6d6dSopenharmony_ci        int32_t prevDestIndex = destIndex - expected[i].newLength;
1242e5b6d6dSopenharmony_ci        if (index == prevSrcIndex) {
1252e5b6d6dSopenharmony_ci            return prevDestIndex;
1262e5b6d6dSopenharmony_ci        } else if (index > prevSrcIndex) {
1272e5b6d6dSopenharmony_ci            if (expected[i].change) {
1282e5b6d6dSopenharmony_ci                // In a change span, map to its end.
1292e5b6d6dSopenharmony_ci                return destIndex;
1302e5b6d6dSopenharmony_ci            } else {
1312e5b6d6dSopenharmony_ci                // In an unchanged span, offset within it.
1322e5b6d6dSopenharmony_ci                return prevDestIndex + (index - prevSrcIndex);
1332e5b6d6dSopenharmony_ci            }
1342e5b6d6dSopenharmony_ci        }
1352e5b6d6dSopenharmony_ci        srcIndex = prevSrcIndex;
1362e5b6d6dSopenharmony_ci        destIndex = prevDestIndex;
1372e5b6d6dSopenharmony_ci    }
1382e5b6d6dSopenharmony_ci    // index is outside the string.
1392e5b6d6dSopenharmony_ci    return destIndex;
1402e5b6d6dSopenharmony_ci}
1412e5b6d6dSopenharmony_ci
1422e5b6d6dSopenharmony_ci}  // namespace
1432e5b6d6dSopenharmony_ci
1442e5b6d6dSopenharmony_ci// For debugging, set -v to see matching edits up to a failure.
1452e5b6d6dSopenharmony_ciUBool TestUtility::checkEqualEdits(IntlTest &test, const UnicodeString &name,
1462e5b6d6dSopenharmony_ci                                   const Edits &e1, const Edits &e2, UErrorCode &errorCode) {
1472e5b6d6dSopenharmony_ci    Edits::Iterator ei1 = e1.getFineIterator();
1482e5b6d6dSopenharmony_ci    Edits::Iterator ei2 = e2.getFineIterator();
1492e5b6d6dSopenharmony_ci    UBool ok = true;
1502e5b6d6dSopenharmony_ci    for (int32_t i = 0; ok; ++i) {
1512e5b6d6dSopenharmony_ci        UBool ei1HasNext = ei1.next(errorCode);
1522e5b6d6dSopenharmony_ci        UBool ei2HasNext = ei2.next(errorCode);
1532e5b6d6dSopenharmony_ci        ok &= test.assertEquals(name + u" next()[" + i + u"]" + __LINE__,
1542e5b6d6dSopenharmony_ci                                ei1HasNext, ei2HasNext);
1552e5b6d6dSopenharmony_ci        ok &= test.assertSuccess(name + u" errorCode[" + i + u"]" + __LINE__, errorCode);
1562e5b6d6dSopenharmony_ci        ok &= test.assertEquals(name + u" edit[" + i + u"]" + __LINE__,
1572e5b6d6dSopenharmony_ci                                printOneEdit(ei1), printOneEdit(ei2));
1582e5b6d6dSopenharmony_ci        if (!ei1HasNext || !ei2HasNext) {
1592e5b6d6dSopenharmony_ci            break;
1602e5b6d6dSopenharmony_ci        }
1612e5b6d6dSopenharmony_ci        test.logln();
1622e5b6d6dSopenharmony_ci    }
1632e5b6d6dSopenharmony_ci    return ok;
1642e5b6d6dSopenharmony_ci}
1652e5b6d6dSopenharmony_ci
1662e5b6d6dSopenharmony_civoid TestUtility::checkEditsIter(
1672e5b6d6dSopenharmony_ci        IntlTest &test,
1682e5b6d6dSopenharmony_ci        const UnicodeString &name,
1692e5b6d6dSopenharmony_ci        Edits::Iterator ei1, Edits::Iterator ei2,  // two equal iterators
1702e5b6d6dSopenharmony_ci        const EditChange expected[], int32_t expLength, UBool withUnchanged,
1712e5b6d6dSopenharmony_ci        UErrorCode &errorCode) {
1722e5b6d6dSopenharmony_ci    test.assertFalse(name + u":" + __LINE__, ei2.findSourceIndex(-1, errorCode));
1732e5b6d6dSopenharmony_ci    test.assertFalse(name + u":" + __LINE__, ei2.findDestinationIndex(-1, errorCode));
1742e5b6d6dSopenharmony_ci
1752e5b6d6dSopenharmony_ci    int32_t expSrcIndex = 0;
1762e5b6d6dSopenharmony_ci    int32_t expDestIndex = 0;
1772e5b6d6dSopenharmony_ci    int32_t expReplIndex = 0;
1782e5b6d6dSopenharmony_ci    for (int32_t expIndex = 0; expIndex < expLength; ++expIndex) {
1792e5b6d6dSopenharmony_ci        const EditChange &expect = expected[expIndex];
1802e5b6d6dSopenharmony_ci        UnicodeString msg = UnicodeString(name).append(u' ') + expIndex;
1812e5b6d6dSopenharmony_ci        if (withUnchanged || expect.change) {
1822e5b6d6dSopenharmony_ci            test.assertTrue(msg + u":" + __LINE__, ei1.next(errorCode));
1832e5b6d6dSopenharmony_ci            test.assertEquals(msg + u":" + __LINE__, expect.change, ei1.hasChange());
1842e5b6d6dSopenharmony_ci            test.assertEquals(msg + u":" + __LINE__, expect.oldLength, ei1.oldLength());
1852e5b6d6dSopenharmony_ci            test.assertEquals(msg + u":" + __LINE__, expect.newLength, ei1.newLength());
1862e5b6d6dSopenharmony_ci            test.assertEquals(msg + u":" + __LINE__, expSrcIndex, ei1.sourceIndex());
1872e5b6d6dSopenharmony_ci            test.assertEquals(msg + u":" + __LINE__, expDestIndex, ei1.destinationIndex());
1882e5b6d6dSopenharmony_ci            test.assertEquals(msg + u":" + __LINE__, expReplIndex, ei1.replacementIndex());
1892e5b6d6dSopenharmony_ci        }
1902e5b6d6dSopenharmony_ci
1912e5b6d6dSopenharmony_ci        if (expect.oldLength > 0) {
1922e5b6d6dSopenharmony_ci            test.assertTrue(msg + u":" + __LINE__, ei2.findSourceIndex(expSrcIndex, errorCode));
1932e5b6d6dSopenharmony_ci            test.assertEquals(msg + u":" + __LINE__, expect.change, ei2.hasChange());
1942e5b6d6dSopenharmony_ci            test.assertEquals(msg + u":" + __LINE__, expect.oldLength, ei2.oldLength());
1952e5b6d6dSopenharmony_ci            test.assertEquals(msg + u":" + __LINE__, expect.newLength, ei2.newLength());
1962e5b6d6dSopenharmony_ci            test.assertEquals(msg + u":" + __LINE__, expSrcIndex, ei2.sourceIndex());
1972e5b6d6dSopenharmony_ci            test.assertEquals(msg + u":" + __LINE__, expDestIndex, ei2.destinationIndex());
1982e5b6d6dSopenharmony_ci            test.assertEquals(msg + u":" + __LINE__, expReplIndex, ei2.replacementIndex());
1992e5b6d6dSopenharmony_ci            if (!withUnchanged) {
2002e5b6d6dSopenharmony_ci                // For some iterators, move past the current range
2012e5b6d6dSopenharmony_ci                // so that findSourceIndex() has to look before the current index.
2022e5b6d6dSopenharmony_ci                ei2.next(errorCode);
2032e5b6d6dSopenharmony_ci                ei2.next(errorCode);
2042e5b6d6dSopenharmony_ci            }
2052e5b6d6dSopenharmony_ci        }
2062e5b6d6dSopenharmony_ci
2072e5b6d6dSopenharmony_ci        if (expect.newLength > 0) {
2082e5b6d6dSopenharmony_ci            test.assertTrue(msg + u":" + __LINE__, ei2.findDestinationIndex(expDestIndex, errorCode));
2092e5b6d6dSopenharmony_ci            test.assertEquals(msg + u":" + __LINE__, expect.change, ei2.hasChange());
2102e5b6d6dSopenharmony_ci            test.assertEquals(msg + u":" + __LINE__, expect.oldLength, ei2.oldLength());
2112e5b6d6dSopenharmony_ci            test.assertEquals(msg + u":" + __LINE__, expect.newLength, ei2.newLength());
2122e5b6d6dSopenharmony_ci            test.assertEquals(msg + u":" + __LINE__, expSrcIndex, ei2.sourceIndex());
2132e5b6d6dSopenharmony_ci            test.assertEquals(msg + u":" + __LINE__, expDestIndex, ei2.destinationIndex());
2142e5b6d6dSopenharmony_ci            test.assertEquals(msg + u":" + __LINE__, expReplIndex, ei2.replacementIndex());
2152e5b6d6dSopenharmony_ci            if (!withUnchanged) {
2162e5b6d6dSopenharmony_ci                // For some iterators, move past the current range
2172e5b6d6dSopenharmony_ci                // so that findSourceIndex() has to look before the current index.
2182e5b6d6dSopenharmony_ci                ei2.next(errorCode);
2192e5b6d6dSopenharmony_ci                ei2.next(errorCode);
2202e5b6d6dSopenharmony_ci            }
2212e5b6d6dSopenharmony_ci        }
2222e5b6d6dSopenharmony_ci
2232e5b6d6dSopenharmony_ci        expSrcIndex += expect.oldLength;
2242e5b6d6dSopenharmony_ci        expDestIndex += expect.newLength;
2252e5b6d6dSopenharmony_ci        if (expect.change) {
2262e5b6d6dSopenharmony_ci            expReplIndex += expect.newLength;
2272e5b6d6dSopenharmony_ci        }
2282e5b6d6dSopenharmony_ci    }
2292e5b6d6dSopenharmony_ci    UnicodeString msg = UnicodeString(name).append(u" end");
2302e5b6d6dSopenharmony_ci    test.assertFalse(msg + u":" + __LINE__, ei1.next(errorCode));
2312e5b6d6dSopenharmony_ci    test.assertFalse(msg + u":" + __LINE__, ei1.hasChange());
2322e5b6d6dSopenharmony_ci    test.assertEquals(msg + u":" + __LINE__, 0, ei1.oldLength());
2332e5b6d6dSopenharmony_ci    test.assertEquals(msg + u":" + __LINE__, 0, ei1.newLength());
2342e5b6d6dSopenharmony_ci    test.assertEquals(msg + u":" + __LINE__, expSrcIndex, ei1.sourceIndex());
2352e5b6d6dSopenharmony_ci    test.assertEquals(msg + u":" + __LINE__, expDestIndex, ei1.destinationIndex());
2362e5b6d6dSopenharmony_ci    test.assertEquals(msg + u":" + __LINE__, expReplIndex, ei1.replacementIndex());
2372e5b6d6dSopenharmony_ci
2382e5b6d6dSopenharmony_ci    test.assertFalse(name + u":" + __LINE__, ei2.findSourceIndex(expSrcIndex, errorCode));
2392e5b6d6dSopenharmony_ci    test.assertFalse(name + u":" + __LINE__, ei2.findDestinationIndex(expDestIndex, errorCode));
2402e5b6d6dSopenharmony_ci
2412e5b6d6dSopenharmony_ci    // Check mapping of all indexes against a simple implementation
2422e5b6d6dSopenharmony_ci    // that works on the expected changes.
2432e5b6d6dSopenharmony_ci    // Iterate once forward, once backward, to cover more runtime conditions.
2442e5b6d6dSopenharmony_ci    int32_t srcLength = expSrcIndex;
2452e5b6d6dSopenharmony_ci    int32_t destLength = expDestIndex;
2462e5b6d6dSopenharmony_ci    std::vector<int32_t> srcIndexes;
2472e5b6d6dSopenharmony_ci    std::vector<int32_t> destIndexes;
2482e5b6d6dSopenharmony_ci    srcIndexes.push_back(-1);
2492e5b6d6dSopenharmony_ci    destIndexes.push_back(-1);
2502e5b6d6dSopenharmony_ci    int32_t srcIndex = 0;
2512e5b6d6dSopenharmony_ci    int32_t destIndex = 0;
2522e5b6d6dSopenharmony_ci    for (int32_t i = 0; i < expLength; ++i) {
2532e5b6d6dSopenharmony_ci        if (expected[i].oldLength > 0) {
2542e5b6d6dSopenharmony_ci            srcIndexes.push_back(srcIndex);
2552e5b6d6dSopenharmony_ci            if (expected[i].oldLength > 1) {
2562e5b6d6dSopenharmony_ci                srcIndexes.push_back(srcIndex + 1);
2572e5b6d6dSopenharmony_ci                if (expected[i].oldLength > 2) {
2582e5b6d6dSopenharmony_ci                    srcIndexes.push_back(srcIndex + expected[i].oldLength - 1);
2592e5b6d6dSopenharmony_ci                }
2602e5b6d6dSopenharmony_ci            }
2612e5b6d6dSopenharmony_ci        }
2622e5b6d6dSopenharmony_ci        if (expected[i].newLength > 0) {
2632e5b6d6dSopenharmony_ci            destIndexes.push_back(destIndex);
2642e5b6d6dSopenharmony_ci            if (expected[i].newLength > 1) {
2652e5b6d6dSopenharmony_ci                destIndexes.push_back(destIndex + 1);
2662e5b6d6dSopenharmony_ci                if (expected[i].newLength > 2) {
2672e5b6d6dSopenharmony_ci                    destIndexes.push_back(destIndex + expected[i].newLength - 1);
2682e5b6d6dSopenharmony_ci                }
2692e5b6d6dSopenharmony_ci            }
2702e5b6d6dSopenharmony_ci        }
2712e5b6d6dSopenharmony_ci        srcIndex += expected[i].oldLength;
2722e5b6d6dSopenharmony_ci        destIndex += expected[i].newLength;
2732e5b6d6dSopenharmony_ci    }
2742e5b6d6dSopenharmony_ci    srcIndexes.push_back(srcLength);
2752e5b6d6dSopenharmony_ci    destIndexes.push_back(destLength);
2762e5b6d6dSopenharmony_ci    srcIndexes.push_back(srcLength + 1);
2772e5b6d6dSopenharmony_ci    destIndexes.push_back(destLength + 1);
2782e5b6d6dSopenharmony_ci    std::reverse(destIndexes.begin(), destIndexes.end());
2792e5b6d6dSopenharmony_ci    // Zig-zag across the indexes to stress next() <-> previous().
2802e5b6d6dSopenharmony_ci    static const int32_t ZIG_ZAG[] = { 0, 1, 2, 3, 2, 1 };
2812e5b6d6dSopenharmony_ci    for (auto i = 0; i < (int32_t)srcIndexes.size(); ++i) {
2822e5b6d6dSopenharmony_ci        for (int32_t ij = 0; ij < UPRV_LENGTHOF(ZIG_ZAG); ++ij) {
2832e5b6d6dSopenharmony_ci            int32_t j = ZIG_ZAG[ij];
2842e5b6d6dSopenharmony_ci            if ((i + j) < (int32_t)srcIndexes.size()) {
2852e5b6d6dSopenharmony_ci                int32_t si = srcIndexes[i + j];
2862e5b6d6dSopenharmony_ci                test.assertEquals(name + u" destIndexFromSrc(" + si + u"):" + __LINE__,
2872e5b6d6dSopenharmony_ci                                  destIndexFromSrc(expected, expLength, srcLength, destLength, si),
2882e5b6d6dSopenharmony_ci                                  ei2.destinationIndexFromSourceIndex(si, errorCode));
2892e5b6d6dSopenharmony_ci            }
2902e5b6d6dSopenharmony_ci        }
2912e5b6d6dSopenharmony_ci    }
2922e5b6d6dSopenharmony_ci    for (auto i = 0; i < (int32_t)destIndexes.size(); ++i) {
2932e5b6d6dSopenharmony_ci        for (int32_t ij = 0; ij < UPRV_LENGTHOF(ZIG_ZAG); ++ij) {
2942e5b6d6dSopenharmony_ci            int32_t j = ZIG_ZAG[ij];
2952e5b6d6dSopenharmony_ci            if ((i + j) < (int32_t)destIndexes.size()) {
2962e5b6d6dSopenharmony_ci                int32_t di = destIndexes[i + j];
2972e5b6d6dSopenharmony_ci                test.assertEquals(name + u" srcIndexFromDest(" + di + u"):" + __LINE__,
2982e5b6d6dSopenharmony_ci                                  srcIndexFromDest(expected, expLength, srcLength, destLength, di),
2992e5b6d6dSopenharmony_ci                                  ei2.sourceIndexFromDestinationIndex(di, errorCode));
3002e5b6d6dSopenharmony_ci            }
3012e5b6d6dSopenharmony_ci        }
3022e5b6d6dSopenharmony_ci    }
3032e5b6d6dSopenharmony_ci}
304