Annotation of nono/lib/test_mystring.cpp, revision 1.1.1.4

1.1       root        1: //
                      2: // nono
                      3: // Copyright (C) 2021 nono project
                      4: // Licensed under nono-license.txt
                      5: //
                      6: 
                      7: #include <vector>
                      8: #include <tuple>
                      9: #include <functional>
                     10: #include "mystring.h"
                     11: 
                     12: // デバッグ文字列を返す
                     13: // プリミティブ型
                     14: template <class T>
                     15: std::string
                     16: ToDebugString(T x) {
                     17:        return std::to_string(x);
                     18: }
                     19: 
                     20: // デバッグ文字列を返す
                     21: // bool 型
                     22: static std::string
                     23: ToDebugString(bool x)
                     24: {
                     25:        return x ? "true" : "false";
                     26: }
                     27: 
                     28: // デバッグ文字列を返す
                     29: // string 型
                     30: static std::string
                     31: ToDebugString(const std::string& x)
                     32: {
                     33:        std::string rv { '"' };
                     34:        // TODO: escape
                     35:        rv += x;
                     36:        rv += '"';
                     37:        return rv;
                     38: }
                     39: 
1.1.1.2   root       40: static std::string __unused
1.1       root       41: ToDebugString(const char *x)
                     42: {
                     43:        return ToDebugString(std::string { x });
                     44: }
                     45: 
1.1.1.2   root       46: // デバッグ文字列を返す
                     47: // std::vector<std::string>
                     48: static std::string
                     49: ToDebugString(const std::vector<std::string>& x)
                     50: {
                     51:        std::string rv;
                     52: 
                     53:        for (const auto& item : x) {
                     54:                if (rv.empty()) {
                     55:                        rv += "{";
                     56:                } else {
                     57:                        rv += ",";
                     58:                }
                     59:                rv += ToDebugString(item);
                     60:        }
                     61:        rv += "}";
                     62:        return rv;
                     63: }
                     64: 
1.1       root       65: // Tuple with ToDebugString
                     66: 
                     67: // 前方宣言
                     68: template <class... Args>
                     69: class TestTuple;
                     70: 
                     71: // デバッグ文字列を返す
                     72: // TestTuple 型
                     73: template <class... Args>
                     74: std::string
                     75: ToDebugString(const TestTuple<Args...>& x)
                     76: {
                     77:        return x.ToDebugString();
                     78: }
                     79: 
                     80: // オレオレタプル
                     81: template <class... Args>
                     82: class TestTuple : public std::tuple<Args...>
                     83: {
                     84:        // 継承コンストラクタ宣言
                     85:        using std::tuple<Args...>::tuple;
                     86: 
                     87:  public:
                     88:        // デバッグ文字列を返す
                     89:        std::string ToDebugString() const {
                     90:                return ToD(std::index_sequence_for<Args...>{});
                     91:        }
                     92: 
                     93:        // std::get のメンバ関数化
                     94:        // 型が決まらないといけないので [] には出来ない。
                     95:        template <size_t i>
                     96:        auto get() const {
                     97:                return std::get<i>(*this);
                     98:        }
                     99: 
                    100:  private:
                    101:        // このへん参照
                    102:        // https://theolizer.com/cpp-school2/cpp-school2-21/
                    103: 
                    104:        template <size_t... indices>
                    105:        std::string ToD(std::index_sequence<indices...>) const {
                    106:                // get<> にはテンプレート引数を渡さないといけないので
                    107:                // 配列要素数がコンパイル時展開になるようにする。
                    108:                // これでタプルの各要素が型ごとに異なる ToDebugString()
                    109:                // の実体関数を呼び出して、結果の文字列が配列に入っている
                    110:                // 状態になる、ようだ。
                    111:                std::string a[] = {
                    112:                        (::ToDebugString(get<indices>()))...
                    113:                };
                    114: 
                    115:                // a[] をよしなに連結すれば良い
                    116:                std::string rv { '{' };
                    117:                bool first = true;
                    118:                for (const auto& s : a) {
                    119:                        if (first) {
                    120:                                first = false;
                    121:                        } else {
                    122:                                rv += ',';
                    123:                        }
                    124:                        rv += s;
                    125:                }
                    126:                rv += '}';
                    127:                return rv;
                    128:        }
                    129: };
                    130: 
                    131: // テストデータ用テーブル
                    132: template <class... Args>
                    133: class TestTable : public std::vector<TestTuple<Args...> >
                    134: {
                    135:        // 継承コンストラクタ宣言
                    136:        using std::vector<TestTuple<Args... > >::vector;
                    137: };
                    138: 
                    139: 
                    140: // Test
                    141: 
                    142: class TestClass
                    143: {
                    144:  public:
                    145:        virtual ~TestClass() {}
                    146: 
                    147:        template <class T, class R>
                    148:        void Fail(T expectobj, R real) {
                    149:                printf("Failed at: %s but %s\n",
                    150:                        ToDebugString(expectobj).c_str(),
                    151:                        ToDebugString(real).c_str());
                    152:                exit(1);
                    153:        }
                    154: 
                    155:        void Test() {
                    156:                Init();
                    157: 
                    158:                for (auto&& t : testlist) {
                    159:                        printf("Testing: %s ", t.name.c_str());
                    160:                        t.func();
                    161:                        printf("Ok\n");
                    162:                }
                    163:        }
                    164: 
                    165:  protected:
1.1.1.2   root      166:        // 継承して、TESTDEF マクロを使って testlist を作ること。
1.1       root      167:        virtual void Init() = 0;
                    168: 
                    169:        // テスト関数のリスト
                    170:        class Entry {
                    171:         public:
                    172:                std::string name;
                    173:                std::function<void(void)> func;
                    174:        };
                    175:        std::vector<Entry> testlist;
                    176: 
                    177: #define TESTDEF(x) testlist.push_back({ #x, [&]() { x(); } })
                    178: 
                    179: 
                    180:        template <class T, class TWhere>
                    181:        void xp_eq(T expect, T actual, const TWhere& where)
                    182:        {
                    183:                // eq なので == で比較。演算子オーバーロード対策。
                    184:                if (expect == actual) {
                    185:                        return;
                    186:                }
                    187: 
                    188:                Fail(where, actual);
                    189:        }
                    190: };
                    191: 
                    192: class Test_MyString : public TestClass
                    193: {
                    194:  protected:
                    195:        void Init() override {
1.1.1.2   root      196:                // TESTDEF マクロに、テスト実行関数の識別子を渡すこと。
1.1       root      197:                TESTDEF(string_ltrim_1);
1.1.1.2   root      198:                TESTDEF(string_rtrim_1);
                    199:                TESTDEF(rtrim_1);
                    200:                TESTDEF(string_trim_1);
                    201:                TESTDEF(startwith_ignorecase_1);
                    202:                TESTDEF(string_split_1);
                    203:                TESTDEF(string_split_2);
1.1.1.3   root      204:                TESTDEF(format_number_1);
1.1.1.4 ! root      205:                TESTDEF(SecToStr_1);
        !           206:                TESTDEF(TimeToStr_1);
1.1.1.2   root      207:        }
                    208: 
                    209:        void string_ltrim_1() {
                    210:                TestTable<std::string, std::string> table = {
                    211:                        { "",           "" },
                    212:                        { "a",          "a" },
                    213:                        { "abc",        "abc" },
                    214:                        { "a ",         "a " },
                    215:                        { " a",         "a" },
                    216:                        { "a \t",       "a \t" },
                    217:                        { "\t a",       "a" },
                    218:                        { "  a  ",      "a  " },
                    219:                        { " abc ",      "abc " },
                    220:                        { "\r\na\r\n",  "a\r\n" },      // 行頭の改行も空白文字になる
                    221:                        { "  ",         "" },
                    222:                };
                    223: 
                    224:                for (const auto& t : table) {
                    225:                        const auto& src = t.get<0>();
                    226:                        const auto& exp = t.get<1>();
                    227: 
                    228:                        xp_eq(exp, string_ltrim(src), t);
                    229:                }
                    230:        }
                    231: 
                    232:        void string_rtrim_1() {
                    233:                TestTable<std::string, std::string> table = {
                    234:                        { "",           "" },
                    235:                        { "a",          "a" },
                    236:                        { "abc",        "abc" },
                    237:                        { "a ",         "a" },
                    238:                        { " a",         " a" },
                    239:                        { "a \t",       "a" },
                    240:                        { "\t a",       "\t a" },
                    241:                        { "  a  ",      "  a" },
                    242:                        { " abc ",      " abc" },
                    243:                        { "\r\na\r\n",  "\r\na" },
                    244:                        { "  ",         "" },
                    245:                };
                    246: 
                    247:                for (const auto& t : table) {
                    248:                        auto src = t.get<0>();
                    249:                        const auto& exp = t.get<1>();
                    250: 
                    251:                        string_rtrim(src);
                    252:                        xp_eq(exp, src, t);
                    253:                }
                    254:        }
                    255: 
                    256:        void rtrim_1() {
                    257:                TestTable<std::string, std::string> table = {
                    258:                        { "",           "" },
                    259:                        { "a",          "a" },
                    260:                        { "abc",        "abc" },
                    261:                        { "a ",         "a" },
                    262:                        { " a",         " a" },
                    263:                        { "a \t",       "a" },
                    264:                        { "\t a",       "\t a" },
                    265:                        { "  a  ",      "  a" },
                    266:                        { " abc ",      " abc" },
                    267:                        { "\r\na\r\n",  "\r\na" },
                    268:                        { "  ",         "" },
                    269:                };
                    270: 
                    271:                for (const auto& t : table) {
                    272:                        const auto& src = t.get<0>();
                    273:                        const auto& exp = t.get<1>();
                    274: 
                    275:                        std::vector<char> buf(src.size() + 1);
                    276:                        memcpy(buf.data(), src.c_str(), buf.size());
                    277:                        rtrim(buf.data());
                    278:                        xp_eq(exp, std::string(buf.data()), t);
                    279:                }
                    280:        }
                    281: 
                    282:        void string_trim_1() {
                    283:                TestTable<std::string, std::string> table = {
                    284:                        { "",           "" },
                    285:                        { "a",          "a" },
                    286:                        { "abc",        "abc" },
                    287:                        { "a ",         "a" },
                    288:                        { " a",         "a" },
                    289:                        { "a \t",       "a" },
                    290:                        { "\t a",       "a" },
                    291:                        { "  a  ",      "a" },
                    292:                        { " abc ",      "abc" },
                    293:                        { "\r\na\r\n",  "a" },
                    294:                        { "  ",         "" },
                    295:                };
                    296: 
                    297:                for (const auto& t : table) {
                    298:                        const auto& src = t.get<0>();
                    299:                        const auto& exp = t.get<1>();
                    300: 
                    301:                        xp_eq(exp, string_trim(src), t);
                    302:                }
1.1       root      303:        }
                    304: 
                    305:        void startwith_ignorecase_1() {
                    306:                TestTable<std::string, std::string, bool> table = {
1.1.1.2   root      307:                        { "ABCDEF",     "A",    true },
                    308:                        { "ABCDEF",     "B",    false },
                    309:                        { "ABCDEF",     "AB",   true },
                    310:                        { "ABCDEF",     "BC",   false },
                    311:                        { "ABCDEF",     "a",    true },
                    312:                        { "ABCDEF",     "b",    false },
                    313:                        { "ABCDEF",     "ab",   true },
                    314:                        { "ABCDEF",     "bc",   false },
                    315:                        { "aBCDEF",     "a",    true },
                    316:                        { "aBCDEF",     "b",    false },
                    317:                        { "aBCDEF",     "ab",   true },
                    318:                        { "aBCDEF",     "ABcd", true },
                    319:                        { "",           "A",    false },
                    320:                        { "",           "",             true }, // ??? これはまだわかる
                    321:                        { "A",          "",             true }, // ??? 概念的には true だが果たして?
1.1       root      322:                };
                    323: 
                    324:                for (auto t : table) {
                    325:                        auto arg0 = t.get<0>();
                    326:                        auto arg1 = t.get<1>();
                    327:                        auto expect = t.get<2>();
                    328: 
                    329:                        xp_eq(expect, starts_with_ignorecase(arg0, arg1), t);
                    330:                }
                    331:        }
                    332: 
1.1.1.2   root      333:        void string_split_1() {
                    334:                TestTable<std::string, std::vector<std::string>> table = {
                    335:                        { "",           { } },
                    336:                        { "ab",         { "ab" } },
                    337:                        { "ab,c",       { "ab", "c" } },
                    338:                        { "ab,",        { "ab", "" } },                 // separator が末尾
                    339:                        { ",a,,",       { "", "a", "", "" } },  // separator は連続しても独立
                    340:                        { ",",          { "", "" } },                   // separator のみ
                    341:                };
                    342: 
                    343:                for (const auto& t : table) {
                    344:                        const auto& src = t.get<0>();
                    345:                        const auto& exp = t.get<1>();
                    346: 
                    347:                        xp_eq(exp, string_split(src, ','), t);
                    348:                }
                    349:        }
                    350: 
                    351:        void string_split_2() {
                    352:                TestTable<std::string, int, std::vector<std::string>> table = {
                    353:                        // 念のため等価のはず
                    354:                        { "",           0, { } },
                    355:                        { "ab",         0, { "ab" } },
                    356:                        { "ab,c",       0, { "ab", "c" } },
                    357:                        { "ab,",        0, { "ab", "" } },
                    358:                        { ",a,,",       0, { "", "a", "", "" } },
                    359:                        { ",",          0, { "", "" } },
                    360: 
                    361:                        { "",           1, { } },
                    362:                        { "ab",         1, { "ab" } },
                    363:                        { "ab,c",       1, { "ab,c" } },
                    364:                        { "ab,",        1, { "ab," } },
                    365:                        { ",a,,",       1, { ",a,," } },
                    366:                        { ",",          1, { "," } },
                    367: 
                    368:                        { "",           2, { } },
                    369:                        { "ab",         2, { "ab" } },
                    370:                        { "ab,c",       2, { "ab", "c" } },
                    371:                        { "ab,",        2, { "ab", "" } },
                    372:                        { "a,b,c",      2, { "a", "b,c" } },
                    373:                        { ",a,,",       2, { "", "a,," } },
                    374:                        { ",",          2, { "", "" } },
                    375:                };
                    376: 
                    377:                for (const auto& t : table) {
                    378:                        const auto& src = t.get<0>();
                    379:                        auto        num = t.get<1>();
                    380:                        const auto& exp = t.get<2>();
                    381: 
                    382:                        xp_eq(exp, string_split(src, ',', num), t);
                    383:                }
1.1       root      384:        }
1.1.1.3   root      385: 
                    386:        void format_number_1() {
                    387:                TestTable<uint64, std::string> table = {
                    388:                        { 0,                    "0" },
                    389:                        { 1,                    "1" },
                    390:                        { 999,                  "999" },
                    391:                        { 1000,                 "1,000" },
                    392:                        { 12345,                "12,345" },
                    393:                        { 123456,               "123,456" },
                    394:                        { 9876543,              "9,876,543" },
                    395:                        { 987654321,    "987,654,321" },
                    396:                        { 1000000000,   "1,000,000,000" },
                    397:                };
                    398: 
                    399:                for (const auto& t : table) {
                    400:                        auto        val = t.get<0>();
                    401:                        const auto& exp = t.get<1>();
                    402: 
                    403:                        xp_eq(exp, format_number(val), t);
                    404:                }
                    405:        }
1.1.1.4 ! root      406: 
        !           407:        void SecToStr_1() {
        !           408:                TestTable<uint64, std::string> table = {
        !           409:                        { 0,                                                "0.000'000'000" },
        !           410:                        { 1,                                                "0.000'000'001" },
        !           411:                        { 999999999,                                "0.999'999'999" },
        !           412:                        { 4300020001,                               "4.300'020'001" },
        !           413:                        { 9999999999,                               "9.999'999'999" },
        !           414:                        { 10000000001,                             "10.000'000'001" },
        !           415:                        { 100000000002,                           "100.000'000'002" },
        !           416:                        { 1000000000003,                         "1000.000'000'003" },
        !           417:                        { 10000000000004,                       "10000.000'000'004" },
        !           418:                        { 100000000000005,                     "100000.000'000'005" },
        !           419:                        { 1000000000000006,                   "1000000.000'000'006" },
        !           420:                        { 10000000000000007,         "10000000.000'000'007" },
        !           421:                        { 100000000000000008,       "100000000.000'000'008" },
        !           422:                };
        !           423: 
        !           424:                for (const auto& t : table) {
        !           425:                        auto        val = t.get<0>();
        !           426:                        const auto& exp = t.get<1>();
        !           427: 
        !           428:                        xp_eq(exp, SecToStr(val), t);
        !           429:                }
        !           430:        }
        !           431: 
        !           432:        void TimeToStr_1() {
        !           433:                TestTable<uint64, std::string> table = {
        !           434:                        { 0,                                                "0.000'000'000" },
        !           435:                        { 1,                                                "0.000'000'001" },
        !           436:                        { 999999999,                                "0.999'999'999" },
        !           437:                        { 4300020001,                               "4.300'020'001" },
        !           438:                        { 9999999999,                               "9.999'999'999" },
        !           439:                        { 10000000001,                             "10.000'000'001" },
        !           440:                        { 100000000002,                         " 1:40.000'000'002" },
        !           441:                        { 1000000000003,                        "16:40.000'000'003" },
        !           442:                        { 10000000000004,                    " 2:46:40.000'000'004" },
        !           443:                        { 100000000000005,              "  1d 03:46:40.000'000'005" },
        !           444:                        { 1000000000000006,             " 11d 13:46:40.000'000'006" },
        !           445:                        { 10000000000000007,    "115d 17:46:40.000'000'007" },
        !           446:                        { 100000000000000008,   "1157d 09:46:40.000'000'008" },
        !           447:                };
        !           448: 
        !           449:                for (const auto& t : table) {
        !           450:                        auto        val = t.get<0>();
        !           451:                        const auto& exp = t.get<1>();
        !           452: 
        !           453:                        xp_eq(exp, TimeToStr(val), t);
        !           454:                }
        !           455:        }
1.1       root      456: };
                    457: 
                    458: int
                    459: main(int ac, char *av[])
                    460: {
                    461:        printf("compiled by ");
                    462: #if defined(__clang_version__)
                    463:        printf("clang %s", __clang_version__);
                    464: #elif defined(__GNUC__) && defined(__VERSION__)
                    465:        printf("gcc %s", __VERSION__);
                    466: #else
                    467:        printf("unknown compiler");
                    468: #endif
                    469:        printf("\n");
                    470: 
                    471:        Test_MyString{}.Test();
                    472:        return 0;
                    473: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.