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

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

unix.superglobalmegacorp.com

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