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

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.2   root      205:        }
                    206: 
                    207:        void string_ltrim_1() {
                    208:                TestTable<std::string, std::string> table = {
                    209:                        { "",           "" },
                    210:                        { "a",          "a" },
                    211:                        { "abc",        "abc" },
                    212:                        { "a ",         "a " },
                    213:                        { " a",         "a" },
                    214:                        { "a \t",       "a \t" },
                    215:                        { "\t a",       "a" },
                    216:                        { "  a  ",      "a  " },
                    217:                        { " abc ",      "abc " },
                    218:                        { "\r\na\r\n",  "a\r\n" },      // 行頭の改行も空白文字になる
                    219:                        { "  ",         "" },
                    220:                };
                    221: 
                    222:                for (const auto& t : table) {
                    223:                        const auto& src = t.get<0>();
                    224:                        const auto& exp = t.get<1>();
                    225: 
                    226:                        xp_eq(exp, string_ltrim(src), t);
                    227:                }
                    228:        }
                    229: 
                    230:        void string_rtrim_1() {
                    231:                TestTable<std::string, std::string> table = {
                    232:                        { "",           "" },
                    233:                        { "a",          "a" },
                    234:                        { "abc",        "abc" },
                    235:                        { "a ",         "a" },
                    236:                        { " a",         " a" },
                    237:                        { "a \t",       "a" },
                    238:                        { "\t a",       "\t a" },
                    239:                        { "  a  ",      "  a" },
                    240:                        { " abc ",      " abc" },
                    241:                        { "\r\na\r\n",  "\r\na" },
                    242:                        { "  ",         "" },
                    243:                };
                    244: 
                    245:                for (const auto& t : table) {
                    246:                        auto src = t.get<0>();
                    247:                        const auto& exp = t.get<1>();
                    248: 
                    249:                        string_rtrim(src);
                    250:                        xp_eq(exp, src, t);
                    251:                }
                    252:        }
                    253: 
                    254:        void rtrim_1() {
                    255:                TestTable<std::string, std::string> table = {
                    256:                        { "",           "" },
                    257:                        { "a",          "a" },
                    258:                        { "abc",        "abc" },
                    259:                        { "a ",         "a" },
                    260:                        { " a",         " a" },
                    261:                        { "a \t",       "a" },
                    262:                        { "\t a",       "\t a" },
                    263:                        { "  a  ",      "  a" },
                    264:                        { " abc ",      " abc" },
                    265:                        { "\r\na\r\n",  "\r\na" },
                    266:                        { "  ",         "" },
                    267:                };
                    268: 
                    269:                for (const auto& t : table) {
                    270:                        const auto& src = t.get<0>();
                    271:                        const auto& exp = t.get<1>();
                    272: 
                    273:                        std::vector<char> buf(src.size() + 1);
                    274:                        memcpy(buf.data(), src.c_str(), buf.size());
                    275:                        rtrim(buf.data());
                    276:                        xp_eq(exp, std::string(buf.data()), t);
                    277:                }
                    278:        }
                    279: 
                    280:        void string_trim_1() {
                    281:                TestTable<std::string, std::string> table = {
                    282:                        { "",           "" },
                    283:                        { "a",          "a" },
                    284:                        { "abc",        "abc" },
                    285:                        { "a ",         "a" },
                    286:                        { " a",         "a" },
                    287:                        { "a \t",       "a" },
                    288:                        { "\t a",       "a" },
                    289:                        { "  a  ",      "a" },
                    290:                        { " abc ",      "abc" },
                    291:                        { "\r\na\r\n",  "a" },
                    292:                        { "  ",         "" },
                    293:                };
                    294: 
                    295:                for (const auto& t : table) {
                    296:                        const auto& src = t.get<0>();
                    297:                        const auto& exp = t.get<1>();
                    298: 
                    299:                        xp_eq(exp, string_trim(src), t);
                    300:                }
1.1       root      301:        }
                    302: 
                    303:        void startwith_ignorecase_1() {
                    304:                TestTable<std::string, std::string, bool> table = {
1.1.1.2   root      305:                        { "ABCDEF",     "A",    true },
                    306:                        { "ABCDEF",     "B",    false },
                    307:                        { "ABCDEF",     "AB",   true },
                    308:                        { "ABCDEF",     "BC",   false },
                    309:                        { "ABCDEF",     "a",    true },
                    310:                        { "ABCDEF",     "b",    false },
                    311:                        { "ABCDEF",     "ab",   true },
                    312:                        { "ABCDEF",     "bc",   false },
                    313:                        { "aBCDEF",     "a",    true },
                    314:                        { "aBCDEF",     "b",    false },
                    315:                        { "aBCDEF",     "ab",   true },
                    316:                        { "aBCDEF",     "ABcd", true },
                    317:                        { "",           "A",    false },
                    318:                        { "",           "",             true }, // ??? これはまだわかる
                    319:                        { "A",          "",             true }, // ??? 概念的には true だが果たして?
1.1       root      320:                };
                    321: 
                    322:                for (auto t : table) {
                    323:                        auto arg0 = t.get<0>();
                    324:                        auto arg1 = t.get<1>();
                    325:                        auto expect = t.get<2>();
                    326: 
                    327:                        xp_eq(expect, starts_with_ignorecase(arg0, arg1), t);
                    328:                }
                    329:        }
                    330: 
1.1.1.2   root      331:        void string_split_1() {
                    332:                TestTable<std::string, std::vector<std::string>> table = {
                    333:                        { "",           { } },
                    334:                        { "ab",         { "ab" } },
                    335:                        { "ab,c",       { "ab", "c" } },
                    336:                        { "ab,",        { "ab", "" } },                 // separator が末尾
                    337:                        { ",a,,",       { "", "a", "", "" } },  // separator は連続しても独立
                    338:                        { ",",          { "", "" } },                   // separator のみ
                    339:                };
                    340: 
                    341:                for (const auto& t : table) {
                    342:                        const auto& src = t.get<0>();
                    343:                        const auto& exp = t.get<1>();
                    344: 
                    345:                        xp_eq(exp, string_split(src, ','), t);
                    346:                }
                    347:        }
                    348: 
                    349:        void string_split_2() {
                    350:                TestTable<std::string, int, std::vector<std::string>> table = {
                    351:                        // 念のため等価のはず
                    352:                        { "",           0, { } },
                    353:                        { "ab",         0, { "ab" } },
                    354:                        { "ab,c",       0, { "ab", "c" } },
                    355:                        { "ab,",        0, { "ab", "" } },
                    356:                        { ",a,,",       0, { "", "a", "", "" } },
                    357:                        { ",",          0, { "", "" } },
                    358: 
                    359:                        { "",           1, { } },
                    360:                        { "ab",         1, { "ab" } },
                    361:                        { "ab,c",       1, { "ab,c" } },
                    362:                        { "ab,",        1, { "ab," } },
                    363:                        { ",a,,",       1, { ",a,," } },
                    364:                        { ",",          1, { "," } },
                    365: 
                    366:                        { "",           2, { } },
                    367:                        { "ab",         2, { "ab" } },
                    368:                        { "ab,c",       2, { "ab", "c" } },
                    369:                        { "ab,",        2, { "ab", "" } },
                    370:                        { "a,b,c",      2, { "a", "b,c" } },
                    371:                        { ",a,,",       2, { "", "a,," } },
                    372:                        { ",",          2, { "", "" } },
                    373:                };
                    374: 
                    375:                for (const auto& t : table) {
                    376:                        const auto& src = t.get<0>();
                    377:                        auto        num = t.get<1>();
                    378:                        const auto& exp = t.get<2>();
                    379: 
                    380:                        xp_eq(exp, string_split(src, ',', num), t);
                    381:                }
1.1       root      382:        }
1.1.1.3 ! root      383: 
        !           384:        void format_number_1() {
        !           385:                TestTable<uint64, std::string> table = {
        !           386:                        { 0,                    "0" },
        !           387:                        { 1,                    "1" },
        !           388:                        { 999,                  "999" },
        !           389:                        { 1000,                 "1,000" },
        !           390:                        { 12345,                "12,345" },
        !           391:                        { 123456,               "123,456" },
        !           392:                        { 9876543,              "9,876,543" },
        !           393:                        { 987654321,    "987,654,321" },
        !           394:                        { 1000000000,   "1,000,000,000" },
        !           395:                };
        !           396: 
        !           397:                for (const auto& t : table) {
        !           398:                        auto        val = t.get<0>();
        !           399:                        const auto& exp = t.get<1>();
        !           400: 
        !           401:                        xp_eq(exp, format_number(val), t);
        !           402:                }
        !           403:        }
1.1       root      404: };
                    405: 
                    406: int
                    407: main(int ac, char *av[])
                    408: {
                    409:        printf("compiled by ");
                    410: #if defined(__clang_version__)
                    411:        printf("clang %s", __clang_version__);
                    412: #elif defined(__GNUC__) && defined(__VERSION__)
                    413:        printf("gcc %s", __VERSION__);
                    414: #else
                    415:        printf("unknown compiler");
                    416: #endif
                    417:        printf("\n");
                    418: 
                    419:        Test_MyString{}.Test();
                    420:        return 0;
                    421: }

unix.superglobalmegacorp.com

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