File: test_bitmask.cpp

package info (click to toggle)
c4core 0.2.7-1
  • links: PTS
  • area: main
  • in suites: forky, sid
  • size: 5,184 kB
  • sloc: cpp: 35,521; python: 2,786; javascript: 414; makefile: 6
file content (389 lines) | stat: -rw-r--r-- 19,568 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
#include <vector>
#include <sstream>

#ifndef C4CORE_SINGLE_HEADER
#include <c4/bitmask.hpp>
#include <c4/std/vector.hpp>
#endif

#include <c4/test.hpp>

#include "./test_enum_common.hpp"

template<typename Enum>
void cmp_enum(Enum lhs, Enum rhs)
{
    using I = typename std::underlying_type<Enum>::type;
    CHECK_EQ(static_cast<I>(lhs), static_cast<I>(rhs));
}

C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast")


//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------


TEST_CASE("str2bm.simple_bitmask")
{
    using namespace c4;
    std::vector<char> str;

    CHECK_EQ(BM_NONE,              str2bm<MyBitmask>("BM_NONE"));
    CHECK_EQ(BM_NONE,              str2bm<MyBitmask>("NONE"));
    CHECK_EQ(BM_NONE,              str2bm<MyBitmask>("0"));
    CHECK_EQ(BM_NONE,              str2bm<MyBitmask>("0x0"));

    CHECK_EQ(BM_FOO,               str2bm<MyBitmask>("BM_FOO"));
    CHECK_EQ(BM_FOO,               str2bm<MyBitmask>("FOO"));
    CHECK_EQ(BM_FOO,               str2bm<MyBitmask>("1"));
    CHECK_EQ(BM_FOO,               str2bm<MyBitmask>("0x1"));
    CHECK_EQ(BM_FOO,               str2bm<MyBitmask>("BM_NONE|0x1"));

    CHECK_EQ(BM_BAR,               str2bm<MyBitmask>("BM_BAR"));
    CHECK_EQ(BM_BAR,               str2bm<MyBitmask>("BAR"));
    CHECK_EQ(BM_BAR,               str2bm<MyBitmask>("2"));
    CHECK_EQ(BM_BAR,               str2bm<MyBitmask>("0x2"));
    CHECK_EQ(BM_BAR,               str2bm<MyBitmask>("BM_NONE|0x2"));

    CHECK_EQ(BM_BAZ,               str2bm<MyBitmask>("BM_BAZ"));
    CHECK_EQ(BM_BAZ,               str2bm<MyBitmask>("BAZ"));
    CHECK_EQ(BM_BAZ,               str2bm<MyBitmask>("4"));
    CHECK_EQ(BM_BAZ,               str2bm<MyBitmask>("0x4"));

    CHECK_EQ(BM_FOO_BAR,           str2bm<MyBitmask>("BM_FOO|BM_BAR"));
    CHECK_EQ(BM_FOO_BAR,           str2bm<MyBitmask>("BM_FOO|BAR"));
    CHECK_EQ(BM_FOO_BAR,           str2bm<MyBitmask>("FOO|BM_BAR"));
    CHECK_EQ(BM_FOO_BAR,           str2bm<MyBitmask>("BM_FOO_BAR"));
    CHECK_EQ(BM_FOO_BAR,           str2bm<MyBitmask>("FOO_BAR"));
    CHECK_EQ(BM_FOO_BAR,           str2bm<MyBitmask>("FOO|BAR"));
    CHECK_EQ(BM_FOO_BAR,           str2bm<MyBitmask>("0x1|0x2"));
    CHECK_EQ(BM_FOO_BAR,           str2bm<MyBitmask>("1|2"));
    CHECK_EQ(BM_FOO_BAR,           str2bm<MyBitmask>("0x3"));
    CHECK_EQ(BM_FOO_BAR,           str2bm<MyBitmask>("3"));

    CHECK_EQ(BM_FOO_BAR_BAZ,       str2bm<MyBitmask>("BM_FOO|BM_BAR|BM_BAZ"));
    CHECK_EQ(BM_FOO_BAR_BAZ,       str2bm<MyBitmask>("BM_FOO|BM_BAR|BAZ"));
    CHECK_EQ(BM_FOO_BAR_BAZ,       str2bm<MyBitmask>("BM_FOO|BAR|BM_BAZ"));
    CHECK_EQ(BM_FOO_BAR_BAZ,       str2bm<MyBitmask>("FOO|BM_BAR|BM_BAZ"));
    CHECK_EQ(BM_FOO_BAR_BAZ,       str2bm<MyBitmask>("FOO|BM_BAR|BAZ"));
    CHECK_EQ(BM_FOO_BAR_BAZ,       str2bm<MyBitmask>("FOO|BAR|BM_BAZ"));
    CHECK_EQ(BM_FOO_BAR_BAZ,       str2bm<MyBitmask>("FOO|BAR|BAZ"));
    CHECK_EQ(BM_FOO_BAR_BAZ,       str2bm<MyBitmask>("FOO_BAR|BAZ"));
    CHECK_EQ(BM_FOO_BAR_BAZ,       str2bm<MyBitmask>("BM_FOO_BAR|BAZ"));
    CHECK_EQ(BM_FOO_BAR_BAZ,       str2bm<MyBitmask>("0x1|BAR|BAZ"));
    CHECK_EQ(BM_FOO_BAR_BAZ,       str2bm<MyBitmask>("FOO|0x2|BAZ"));
    CHECK_EQ(BM_FOO_BAR_BAZ,       str2bm<MyBitmask>("FOO|BAR|0x4"));
    CHECK_EQ(BM_FOO_BAR_BAZ,       str2bm<MyBitmask>("0x1|0x2|0x4"));
    CHECK_EQ(BM_FOO_BAR_BAZ,       str2bm<MyBitmask>("0x7"));
    CHECK_EQ(BM_FOO_BAR_BAZ,       str2bm<MyBitmask>("7"));
}

TEST_CASE("str2bm.scoped_bitmask")
{
    using namespace c4;
    std::vector<char> str;
    using bmt = MyBitmaskClass;

    cmp_enum(bmt::BM_NONE,              (bmt)str2bm<bmt>("MyBitmaskClass::BM_NONE"));
    cmp_enum(bmt::BM_FOO,               (bmt)str2bm<bmt>("MyBitmaskClass::BM_FOO"));
    cmp_enum(bmt::BM_BAR,               (bmt)str2bm<bmt>("MyBitmaskClass::BM_BAR"));
    cmp_enum(bmt::BM_BAZ,               (bmt)str2bm<bmt>("MyBitmaskClass::BM_BAZ"));
    cmp_enum(bmt::BM_FOO_BAR,           (bmt)str2bm<bmt>("MyBitmaskClass::BM_FOO_BAR"));
    cmp_enum(bmt::BM_FOO_BAR_BAZ,       (bmt)str2bm<bmt>("MyBitmaskClass::BM_FOO_BAR_BAZ"));
    cmp_enum(bmt::BM_NONE,              (bmt)str2bm<bmt>("BM_NONE"));
    cmp_enum(bmt::BM_FOO,               (bmt)str2bm<bmt>("BM_FOO"));
    cmp_enum(bmt::BM_BAR,               (bmt)str2bm<bmt>("BM_BAR"));
    cmp_enum(bmt::BM_BAZ,               (bmt)str2bm<bmt>("BM_BAZ"));
    cmp_enum(bmt::BM_FOO_BAR,           (bmt)str2bm<bmt>("BM_FOO_BAR"));
    cmp_enum(bmt::BM_FOO_BAR_BAZ,       (bmt)str2bm<bmt>("BM_FOO_BAR_BAZ"));
    cmp_enum(bmt::BM_NONE,              (bmt)str2bm<bmt>("NONE"));
    cmp_enum(bmt::BM_FOO,               (bmt)str2bm<bmt>("FOO"));
    cmp_enum(bmt::BM_BAR,               (bmt)str2bm<bmt>("BAR"));
    cmp_enum(bmt::BM_BAZ,               (bmt)str2bm<bmt>("BAZ"));
    cmp_enum(bmt::BM_FOO_BAR,           (bmt)str2bm<bmt>("FOO_BAR"));
    cmp_enum(bmt::BM_FOO_BAR_BAZ,       (bmt)str2bm<bmt>("FOO_BAR_BAZ"));

    cmp_enum(bmt::BM_NONE,              (bmt)str2bm<bmt>("NONE"));
    cmp_enum(bmt::BM_NONE,              (bmt)str2bm<bmt>("BM_NONE"));
    cmp_enum(bmt::BM_NONE,              (bmt)str2bm<bmt>("MyBitmaskClass::BM_NONE"));
    cmp_enum(bmt::BM_NONE,              (bmt)str2bm<bmt>("0"));
    cmp_enum(bmt::BM_NONE,              (bmt)str2bm<bmt>("0x0"));
    cmp_enum(bmt::BM_FOO,               (bmt)str2bm<bmt>("FOO"));
    cmp_enum(bmt::BM_FOO,               (bmt)str2bm<bmt>("BM_FOO"));
    cmp_enum(bmt::BM_FOO,               (bmt)str2bm<bmt>("MyBitmaskClass::BM_FOO"));
    cmp_enum(bmt::BM_FOO,               (bmt)str2bm<bmt>("1"));
    cmp_enum(bmt::BM_FOO,               (bmt)str2bm<bmt>("0x1"));
    cmp_enum(bmt::BM_FOO,               (bmt)str2bm<bmt>("NONE|0x1"));
    cmp_enum(bmt::BM_FOO,               (bmt)str2bm<bmt>("BM_NONE|0x1"));
    cmp_enum(bmt::BM_FOO,               (bmt)str2bm<bmt>("MyBitmaskClass::BM_NONE|0x1"));
    cmp_enum(bmt::BM_BAR,               (bmt)str2bm<bmt>("BAR"));
    cmp_enum(bmt::BM_BAR,               (bmt)str2bm<bmt>("BM_BAR"));
    cmp_enum(bmt::BM_BAR,               (bmt)str2bm<bmt>("MyBitmaskClass::BM_BAR"));
    cmp_enum(bmt::BM_BAR,               (bmt)str2bm<bmt>("2"));
    cmp_enum(bmt::BM_BAR,               (bmt)str2bm<bmt>("0x2"));
    cmp_enum(bmt::BM_BAZ,               (bmt)str2bm<bmt>("BAZ"));
    cmp_enum(bmt::BM_BAZ,               (bmt)str2bm<bmt>("BM_BAZ"));
    cmp_enum(bmt::BM_BAZ,               (bmt)str2bm<bmt>("MyBitmaskClass::BM_BAZ"));
    cmp_enum(bmt::BM_BAR,               (bmt)str2bm<bmt>("BM_NONE|0x2"));
    cmp_enum(bmt::BM_BAR,               (bmt)str2bm<bmt>("MyBitmaskClass::BM_NONE|0x2"));
    cmp_enum(bmt::BM_BAZ,               (bmt)str2bm<bmt>("4"));
    cmp_enum(bmt::BM_BAZ,               (bmt)str2bm<bmt>("0x4"));
    cmp_enum(bmt::BM_FOO_BAR,           (bmt)str2bm<bmt>("BM_FOO|BM_BAR"));
    cmp_enum(bmt::BM_FOO_BAR,           (bmt)str2bm<bmt>("MyBitmaskClass::BM_FOO|MyBitmaskClass::BM_BAR"));
    cmp_enum(bmt::BM_FOO_BAR,           (bmt)str2bm<bmt>("BM_FOO|BAR"));
    cmp_enum(bmt::BM_FOO_BAR,           (bmt)str2bm<bmt>("MyBitmaskClass::BM_FOO|BAR"));
    cmp_enum(bmt::BM_FOO_BAR,           (bmt)str2bm<bmt>("FOO|BM_BAR"));
    cmp_enum(bmt::BM_FOO_BAR,           (bmt)str2bm<bmt>("FOO|MyBitmaskClass::BM_BAR"));
    cmp_enum(bmt::BM_FOO_BAR,           (bmt)str2bm<bmt>("BM_FOO_BAR"));
    cmp_enum(bmt::BM_FOO_BAR,           (bmt)str2bm<bmt>("MyBitmaskClass::BM_FOO_BAR"));
    cmp_enum(bmt::BM_FOO_BAR,           (bmt)str2bm<bmt>("FOO_BAR"));
    cmp_enum(bmt::BM_FOO_BAR,           (bmt)str2bm<bmt>("FOO|BAR"));
    cmp_enum(bmt::BM_FOO_BAR,           (bmt)str2bm<bmt>("0x1|0x2"));
    cmp_enum(bmt::BM_FOO_BAR,           (bmt)str2bm<bmt>("1|2"));
    cmp_enum(bmt::BM_FOO_BAR,           (bmt)str2bm<bmt>("0x3"));
    cmp_enum(bmt::BM_FOO_BAR,           (bmt)str2bm<bmt>("3"));
    cmp_enum(bmt::BM_FOO_BAR_BAZ,       (bmt)str2bm<bmt>("BM_FOO|BM_BAR|BM_BAZ"));
    cmp_enum(bmt::BM_FOO_BAR_BAZ,       (bmt)str2bm<bmt>("MyBitmaskClass::BM_FOO|MyBitmaskClass::BM_BAR|MyBitmaskClass::BM_BAZ"));
    cmp_enum(bmt::BM_FOO_BAR_BAZ,       (bmt)str2bm<bmt>("BM_FOO|BM_BAR|BAZ"));
    cmp_enum(bmt::BM_FOO_BAR_BAZ,       (bmt)str2bm<bmt>("MyBitmaskClass::BM_FOO|MyBitmaskClass::BM_BAR|BAZ"));
    cmp_enum(bmt::BM_FOO_BAR_BAZ,       (bmt)str2bm<bmt>("BM_FOO|BAR|BM_BAZ"));
    cmp_enum(bmt::BM_FOO_BAR_BAZ,       (bmt)str2bm<bmt>("BM_FOO|BAR|MyBitmaskClass::BM_BAZ"));
    cmp_enum(bmt::BM_FOO_BAR_BAZ,       (bmt)str2bm<bmt>("FOO|BM_BAR|BM_BAZ"));
    cmp_enum(bmt::BM_FOO_BAR_BAZ,       (bmt)str2bm<bmt>("FOO|MyBitmaskClass::BM_BAR|MyBitmaskClass::BM_BAZ"));
    cmp_enum(bmt::BM_FOO_BAR_BAZ,       (bmt)str2bm<bmt>("FOO|BM_BAR|BAZ"));
    cmp_enum(bmt::BM_FOO_BAR_BAZ,       (bmt)str2bm<bmt>("FOO|MyBitmaskClass::BM_BAR|BAZ"));
    cmp_enum(bmt::BM_FOO_BAR_BAZ,       (bmt)str2bm<bmt>("FOO|BAR|BM_BAZ"));
    cmp_enum(bmt::BM_FOO_BAR_BAZ,       (bmt)str2bm<bmt>("FOO|BAR|MyBitmaskClass::BM_BAZ"));
    cmp_enum(bmt::BM_FOO_BAR_BAZ,       (bmt)str2bm<bmt>("FOO|BAR|BAZ"));
    cmp_enum(bmt::BM_FOO_BAR_BAZ,       (bmt)str2bm<bmt>("FOO_BAR|BAZ"));
    cmp_enum(bmt::BM_FOO_BAR_BAZ,       (bmt)str2bm<bmt>("MyBitmaskClass::BM_FOO_BAR|BAZ"));
    cmp_enum(bmt::BM_FOO_BAR_BAZ,       (bmt)str2bm<bmt>("0x1|BAR|BAZ"));
    cmp_enum(bmt::BM_FOO_BAR_BAZ,       (bmt)str2bm<bmt>("FOO|0x2|BAZ"));
    cmp_enum(bmt::BM_FOO_BAR_BAZ,       (bmt)str2bm<bmt>("FOO|BAR|0x4"));
    cmp_enum(bmt::BM_FOO_BAR_BAZ,       (bmt)str2bm<bmt>("0x1|0x2|0x4"));
    cmp_enum(bmt::BM_FOO_BAR_BAZ,       (bmt)str2bm<bmt>("0x7"));
    cmp_enum(bmt::BM_FOO_BAR_BAZ,       (bmt)str2bm<bmt>("0x7"));
}


//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//----------------------------------------------------------------------------

template<class Enum>
const char* do_bm2str(Enum e, std::vector<char> *s, c4::EnumOffsetType which)
{
    size_t len = c4::bm2str<Enum>(e, nullptr, 0, which);
    C4_CHECK(len > 0);
    s->resize(len);
    C4_CHECK(s->data() != nullptr);
    c4::bm2str<Enum>(e, s->data(), s->size(), which);
    return s->data();
}

TEST_CASE("bm2str.simple_bitmask")
{
    using namespace c4;
    std::vector<char> str;

    CHECK_STREQ(do_bm2str(BM_NONE,        &str, EOFFS_NONE), "BM_NONE");
    CHECK_STREQ(do_bm2str(BM_FOO,         &str, EOFFS_NONE), "BM_FOO");
    CHECK_STREQ(do_bm2str(BM_BAR,         &str, EOFFS_NONE), "BM_BAR");
    CHECK_STREQ(do_bm2str(BM_BAZ,         &str, EOFFS_NONE), "BM_BAZ");
    CHECK_STREQ(do_bm2str(BM_FOO_BAR,     &str, EOFFS_NONE), "BM_FOO_BAR");
    CHECK_STREQ(do_bm2str(BM_FOO_BAR_BAZ, &str, EOFFS_NONE), "BM_FOO_BAR_BAZ");
    CHECK_STREQ(do_bm2str(BM_NONE,        &str, EOFFS_CLS ), "BM_NONE");
    CHECK_STREQ(do_bm2str(BM_FOO,         &str, EOFFS_CLS ), "BM_FOO");
    CHECK_STREQ(do_bm2str(BM_BAR,         &str, EOFFS_CLS ), "BM_BAR");
    CHECK_STREQ(do_bm2str(BM_BAZ,         &str, EOFFS_CLS ), "BM_BAZ");
    CHECK_STREQ(do_bm2str(BM_FOO_BAR,     &str, EOFFS_CLS ), "BM_FOO_BAR");
    CHECK_STREQ(do_bm2str(BM_FOO_BAR_BAZ, &str, EOFFS_CLS ), "BM_FOO_BAR_BAZ");
    CHECK_STREQ(do_bm2str(BM_NONE,        &str, EOFFS_PFX ), "NONE");
    CHECK_STREQ(do_bm2str(BM_FOO,         &str, EOFFS_PFX ), "FOO");
    CHECK_STREQ(do_bm2str(BM_BAR,         &str, EOFFS_PFX ), "BAR");
    CHECK_STREQ(do_bm2str(BM_BAZ,         &str, EOFFS_PFX ), "BAZ");
    CHECK_STREQ(do_bm2str(BM_FOO_BAR,     &str, EOFFS_PFX ), "FOO_BAR");
    CHECK_STREQ(do_bm2str(BM_FOO_BAR_BAZ, &str, EOFFS_PFX ), "FOO_BAR_BAZ");
}

TEST_CASE("bm2str.scoped_bitmask")
{
    using namespace c4;
    std::vector<char> str;

    CHECK_STREQ(do_bm2str(MyBitmaskClass::BM_NONE,        &str, EOFFS_NONE), "MyBitmaskClass::BM_NONE");
    CHECK_STREQ(do_bm2str(MyBitmaskClass::BM_FOO,         &str, EOFFS_NONE), "MyBitmaskClass::BM_FOO");
    CHECK_STREQ(do_bm2str(MyBitmaskClass::BM_BAR,         &str, EOFFS_NONE), "MyBitmaskClass::BM_BAR");
    CHECK_STREQ(do_bm2str(MyBitmaskClass::BM_BAZ,         &str, EOFFS_NONE), "MyBitmaskClass::BM_BAZ");
    CHECK_STREQ(do_bm2str(MyBitmaskClass::BM_FOO_BAR,     &str, EOFFS_NONE), "MyBitmaskClass::BM_FOO_BAR");
    CHECK_STREQ(do_bm2str(MyBitmaskClass::BM_FOO_BAR_BAZ, &str, EOFFS_NONE), "MyBitmaskClass::BM_FOO_BAR_BAZ");
    CHECK_STREQ(do_bm2str(MyBitmaskClass::BM_NONE,        &str, EOFFS_CLS ), "BM_NONE");
    CHECK_STREQ(do_bm2str(MyBitmaskClass::BM_FOO,         &str, EOFFS_CLS ), "BM_FOO");
    CHECK_STREQ(do_bm2str(MyBitmaskClass::BM_BAR,         &str, EOFFS_CLS ), "BM_BAR");
    CHECK_STREQ(do_bm2str(MyBitmaskClass::BM_BAZ,         &str, EOFFS_CLS ), "BM_BAZ");
    CHECK_STREQ(do_bm2str(MyBitmaskClass::BM_FOO_BAR,     &str, EOFFS_CLS ), "BM_FOO_BAR");
    CHECK_STREQ(do_bm2str(MyBitmaskClass::BM_FOO_BAR_BAZ, &str, EOFFS_CLS ), "BM_FOO_BAR_BAZ");
    CHECK_STREQ(do_bm2str(MyBitmaskClass::BM_NONE,        &str, EOFFS_PFX ), "NONE");
    CHECK_STREQ(do_bm2str(MyBitmaskClass::BM_FOO,         &str, EOFFS_PFX ), "FOO");
    CHECK_STREQ(do_bm2str(MyBitmaskClass::BM_BAR,         &str, EOFFS_PFX ), "BAR");
    CHECK_STREQ(do_bm2str(MyBitmaskClass::BM_BAZ,         &str, EOFFS_PFX ), "BAZ");
    CHECK_STREQ(do_bm2str(MyBitmaskClass::BM_FOO_BAR,     &str, EOFFS_PFX ), "FOO_BAR");
    CHECK_STREQ(do_bm2str(MyBitmaskClass::BM_FOO_BAR_BAZ, &str, EOFFS_PFX ), "FOO_BAR_BAZ");
}


//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//----------------------------------------------------------------------------

template<class Enum>
std::string do_bm2stream(Enum e, c4::EnumOffsetType which)
{
    std::stringstream ss;
    c4::bm2stream<Enum>(ss, e, which);
    return ss.str();
}

TEST_CASE("bm2stream.simple_bitmask")
{
    using namespace c4;

    CHECK_EQ(do_bm2stream(BM_NONE,        EOFFS_NONE), "BM_NONE");
    CHECK_EQ(do_bm2stream(BM_FOO,         EOFFS_NONE), "BM_FOO");
    CHECK_EQ(do_bm2stream(BM_BAR,         EOFFS_NONE), "BM_BAR");
    CHECK_EQ(do_bm2stream(BM_BAZ,         EOFFS_NONE), "BM_BAZ");
    CHECK_EQ(do_bm2stream(BM_FOO_BAR,     EOFFS_NONE), "BM_FOO_BAR");
    CHECK_EQ(do_bm2stream(BM_FOO_BAR_BAZ, EOFFS_NONE), "BM_FOO_BAR_BAZ");
    CHECK_EQ(do_bm2stream(BM_NONE,        EOFFS_CLS ), "BM_NONE");
    CHECK_EQ(do_bm2stream(BM_FOO,         EOFFS_CLS ), "BM_FOO");
    CHECK_EQ(do_bm2stream(BM_BAR,         EOFFS_CLS ), "BM_BAR");
    CHECK_EQ(do_bm2stream(BM_BAZ,         EOFFS_CLS ), "BM_BAZ");
    CHECK_EQ(do_bm2stream(BM_FOO_BAR,     EOFFS_CLS ), "BM_FOO_BAR");
    CHECK_EQ(do_bm2stream(BM_FOO_BAR_BAZ, EOFFS_CLS ), "BM_FOO_BAR_BAZ");
    CHECK_EQ(do_bm2stream(BM_NONE,        EOFFS_PFX ), "NONE");
    CHECK_EQ(do_bm2stream(BM_FOO,         EOFFS_PFX ), "FOO");
    CHECK_EQ(do_bm2stream(BM_BAR,         EOFFS_PFX ), "BAR");
    CHECK_EQ(do_bm2stream(BM_BAZ,         EOFFS_PFX ), "BAZ");
    CHECK_EQ(do_bm2stream(BM_FOO_BAR,     EOFFS_PFX ), "FOO_BAR");
    CHECK_EQ(do_bm2stream(BM_FOO_BAR_BAZ, EOFFS_PFX ), "FOO_BAR_BAZ");
}

TEST_CASE("bm2stream.scoped_bitmask")
{
    using namespace c4;

    CHECK_EQ(do_bm2stream(MyBitmaskClass::BM_NONE,        EOFFS_NONE), "MyBitmaskClass::BM_NONE");
    CHECK_EQ(do_bm2stream(MyBitmaskClass::BM_FOO,         EOFFS_NONE), "MyBitmaskClass::BM_FOO");
    CHECK_EQ(do_bm2stream(MyBitmaskClass::BM_BAR,         EOFFS_NONE), "MyBitmaskClass::BM_BAR");
    CHECK_EQ(do_bm2stream(MyBitmaskClass::BM_BAZ,         EOFFS_NONE), "MyBitmaskClass::BM_BAZ");
    CHECK_EQ(do_bm2stream(MyBitmaskClass::BM_FOO_BAR,     EOFFS_NONE), "MyBitmaskClass::BM_FOO_BAR");
    CHECK_EQ(do_bm2stream(MyBitmaskClass::BM_FOO_BAR_BAZ, EOFFS_NONE), "MyBitmaskClass::BM_FOO_BAR_BAZ");
    CHECK_EQ(do_bm2stream(MyBitmaskClass::BM_NONE,        EOFFS_CLS ), "BM_NONE");
    CHECK_EQ(do_bm2stream(MyBitmaskClass::BM_FOO,         EOFFS_CLS ), "BM_FOO");
    CHECK_EQ(do_bm2stream(MyBitmaskClass::BM_BAR,         EOFFS_CLS ), "BM_BAR");
    CHECK_EQ(do_bm2stream(MyBitmaskClass::BM_BAZ,         EOFFS_CLS ), "BM_BAZ");
    CHECK_EQ(do_bm2stream(MyBitmaskClass::BM_FOO_BAR,     EOFFS_CLS ), "BM_FOO_BAR");
    CHECK_EQ(do_bm2stream(MyBitmaskClass::BM_FOO_BAR_BAZ, EOFFS_CLS ), "BM_FOO_BAR_BAZ");
    CHECK_EQ(do_bm2stream(MyBitmaskClass::BM_NONE,        EOFFS_PFX ), "NONE");
    CHECK_EQ(do_bm2stream(MyBitmaskClass::BM_FOO,         EOFFS_PFX ), "FOO");
    CHECK_EQ(do_bm2stream(MyBitmaskClass::BM_BAR,         EOFFS_PFX ), "BAR");
    CHECK_EQ(do_bm2stream(MyBitmaskClass::BM_BAZ,         EOFFS_PFX ), "BAZ");
    CHECK_EQ(do_bm2stream(MyBitmaskClass::BM_FOO_BAR,     EOFFS_PFX ), "FOO_BAR");
    CHECK_EQ(do_bm2stream(MyBitmaskClass::BM_FOO_BAR_BAZ, EOFFS_PFX ), "FOO_BAR_BAZ");
}

TEST_CASE("bm2stream.simple_bitmask_without_null_symbol")
{
    using namespace c4;

    CHECK_EQ(do_bm2stream(BM_KABOOM, EOFFS_NONE), "KABOOM");
    CHECK_EQ(do_bm2stream<BmWithoutNull>((BmWithoutNull)0, EOFFS_NONE), "0");
}

TEST_CASE("bm2stream.bitmask_class_without_null_symbol")
{
    using namespace c4;

    CHECK_EQ(do_bm2stream(BmClassWithoutNull::BM_KABOOM, EOFFS_PFX), "KABOOM");
    CHECK_EQ(do_bm2stream<BmClassWithoutNull>((BmClassWithoutNull)0, EOFFS_NONE), "0");
}


//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//----------------------------------------------------------------------------

// TODO
template<typename Enum>
void test_bm2str()
{
    using namespace c4;
    using I = typename std::underlying_type<Enum>::type;
    int combination_depth = 4;
    auto syms = esyms<Enum>();

    std::vector<int> indices;
    std::string str;
    std::vector<char> ws;
    I val = 0, res;
    size_t len;

    for(int k = 1; k <= combination_depth; ++k)
    {
        indices.clear();
        indices.resize(static_cast<size_t>(k));
        while(1)
        {
            str.clear();
            val = 0;
            for(auto i : indices)
            {
                if(!str.empty()) str += '|';
                str += syms[i].name;
                val |= static_cast<I>(syms[i].value);
                //printf("%d", i);
            }
            //len = bm2str<Enum>(val); // needed length
            //ws.resize(len);
            //bm2str<Enum>(val, &ws[0], len);
            //printf(": %s (%zu) %s\n", str.c_str(), (uint64_t)val, ws.data());

            res = str2bm<Enum>(str.data());
            CHECK_EQ(res, val);

            len = bm2str<Enum>(res); // needed length
            ws.resize(len);
            bm2str<Enum>(val, &ws[0], len);
            res = str2bm<Enum>(ws.data());
            CHECK_EQ(res, val);

            // write a string with the bitmask as an int
            c4::catrs(&ws, val);
            res = str2bm<Enum>(str.data());
            CHECK_EQ(res, val);

            bool carry = true;
            for(size_t i = static_cast<size_t>(k-1); i != size_t(-1); --i)
            {
                if(indices[i] + 1 < syms.size())
                {
                    ++indices[i];
                    carry = false;
                    break;
                }
                else
                {
                    indices[i] = 0;
                }
            }
            if(carry)
            {
                break;
            }
        } // while(1)
    } // for k
}

C4_SUPPRESS_WARNING_GCC_CLANG_POP