1 // Author: Derek Barnett
2
3 #include <algorithm>
4 #include <cstdint>
5 #include <iostream>
6 #include <limits>
7 #include <map>
8 #include <string>
9 #include <typeinfo>
10 #include <vector>
11
12 #include <gtest/gtest.h>
13 #include <boost/type_traits/is_convertible.hpp>
14
15 #include <pbbam/BamTagCodec.h>
16 #include <pbbam/SamTagCodec.h>
17 #include <pbbam/TagCollection.h>
18
19 using namespace PacBio;
20 using namespace PacBio::BAM;
21
TEST(TagTest,TagConstruction)22 TEST(TagTest, TagConstruction)
23 {
24 int8_t i8 = 0;
25 uint8_t u8 = 0;
26 int16_t i16 = 0;
27 uint16_t u16 = 0;
28 int32_t i32 = 0;
29 uint32_t u32 = 0;
30 float f = 0.0;
31 std::string str = "";
32 std::vector<int8_t> i8_array;
33 std::vector<uint8_t> u8_array;
34 std::vector<int16_t> i16_array;
35 std::vector<uint16_t> u16_array;
36 std::vector<int32_t> i32_array;
37 std::vector<uint32_t> u32_Array;
38 std::vector<float> float_array;
39
40 signed char c = 'A';
41 unsigned char uc = 'A';
42
43 Tag i8Tag(i8);
44 Tag u8Tag(u8);
45 Tag i16Tag(i16);
46 Tag u16Tag(u16);
47 Tag i32Tag(i32);
48 Tag u32Tag(u32);
49 Tag floatTag(f);
50 Tag stringTag(str);
51 Tag i8_array_Tag(i8_array);
52 Tag u8_array_Tag(u8_array);
53 Tag i16_array_Tag(i16_array);
54 Tag u16_array_Tag(u16_array);
55 Tag i32_array_Tag(i32_array);
56 Tag u32_array_Tag(u32_Array);
57 Tag float_array_Tag(float_array);
58
59 Tag charTag(c, TagModifier::ASCII_CHAR);
60 Tag ucharTag(uc, TagModifier::ASCII_CHAR);
61
62 EXPECT_TRUE(i8Tag.Type() == TagDataType::INT8);
63 EXPECT_TRUE(u8Tag.Type() == TagDataType::UINT8);
64 EXPECT_TRUE(i16Tag.Type() == TagDataType::INT16);
65 EXPECT_TRUE(u16Tag.Type() == TagDataType::UINT16);
66 EXPECT_TRUE(i32Tag.Type() == TagDataType::INT32);
67 EXPECT_TRUE(u32Tag.Type() == TagDataType::UINT32);
68 EXPECT_TRUE(floatTag.Type() == TagDataType::FLOAT);
69 EXPECT_TRUE(stringTag.Type() == TagDataType::STRING);
70 EXPECT_TRUE(i8_array_Tag.Type() == TagDataType::INT8_ARRAY);
71 EXPECT_TRUE(u8_array_Tag.Type() == TagDataType::UINT8_ARRAY);
72 EXPECT_TRUE(i16_array_Tag.Type() == TagDataType::INT16_ARRAY);
73 EXPECT_TRUE(u16_array_Tag.Type() == TagDataType::UINT16_ARRAY);
74 EXPECT_TRUE(i32_array_Tag.Type() == TagDataType::INT32_ARRAY);
75 EXPECT_TRUE(u32_array_Tag.Type() == TagDataType::UINT32_ARRAY);
76 EXPECT_TRUE(float_array_Tag.Type() == TagDataType::FLOAT_ARRAY);
77
78 EXPECT_TRUE(charTag.ToAscii() == 'A');
79 EXPECT_TRUE(ucharTag.ToAscii() == 'A');
80 }
81
TEST(TagTest,CopyAndCompare)82 TEST(TagTest, CopyAndCompare)
83 {
84 int8_t i8 = 0;
85 uint8_t u8 = 0;
86 int16_t i16 = 0;
87 uint16_t u16 = 0;
88 int32_t i32 = 0;
89 uint32_t u32 = 0;
90 float f = 0.0;
91 std::string str = "";
92 std::vector<int8_t> i8_array;
93 std::vector<uint8_t> u8_array;
94 std::vector<int16_t> i16_array;
95 std::vector<uint16_t> u16_array;
96 std::vector<int32_t> i32_array;
97 std::vector<uint32_t> u32_Array;
98 std::vector<float> float_array;
99
100 Tag i8Tag(i8);
101 Tag u8Tag(u8);
102 Tag i16Tag(i16);
103 Tag u16Tag(u16);
104 Tag i32Tag(i32);
105 Tag u32Tag(u32);
106 Tag floatTag(f);
107 Tag stringTag(str);
108 Tag i8_array_Tag(i8_array);
109 Tag u8_array_Tag(u8_array);
110 Tag i16_array_Tag(i16_array);
111 Tag u16_array_Tag(u16_array);
112 Tag i32_array_Tag(i32_array);
113 Tag u32_array_Tag(u32_Array);
114 Tag float_array_Tag(float_array);
115
116 Tag i8Tag2 = i8Tag;
117 Tag u8Tag2 = u8Tag;
118 Tag i16Tag2 = i16Tag;
119 Tag u16Tag2 = u16Tag;
120 Tag i32Tag2 = i32Tag;
121 Tag u32Tag2 = u32Tag;
122 Tag floatTag2 = floatTag;
123 Tag stringTag2 = stringTag;
124 Tag i8_array_Tag2 = i8_array_Tag;
125 Tag u8_array_Tag2 = u8_array_Tag;
126 Tag i16_array_Tag2 = i16_array_Tag;
127 Tag u16_array_Tag2 = u16_array_Tag;
128 Tag i32_array_Tag2 = i32_array_Tag;
129 Tag u32_array_Tag2 = u32_array_Tag;
130 Tag float_array_Tag2 = float_array_Tag;
131
132 EXPECT_EQ(i8Tag, i8Tag2);
133 EXPECT_EQ(u8Tag, u8Tag2);
134 EXPECT_EQ(i16Tag, i16Tag2);
135 EXPECT_EQ(u16Tag, u16Tag2);
136 EXPECT_EQ(i32Tag, i32Tag2);
137 EXPECT_EQ(u32Tag, u32Tag2);
138 EXPECT_EQ(floatTag, floatTag2);
139 EXPECT_EQ(stringTag, stringTag2);
140 EXPECT_EQ(i8_array_Tag, i8_array_Tag2);
141 EXPECT_EQ(u8_array_Tag, u8_array_Tag2);
142 EXPECT_EQ(i16_array_Tag, i16_array_Tag2);
143 EXPECT_EQ(u16_array_Tag, u16_array_Tag2);
144 EXPECT_EQ(i32_array_Tag, i32_array_Tag2);
145 EXPECT_EQ(u32_array_Tag, u32_array_Tag2);
146 EXPECT_EQ(float_array_Tag, float_array_Tag2);
147 }
148
TEST(TagTest,Type_None)149 TEST(TagTest, Type_None)
150 {
151 Tag tag;
152
153 EXPECT_TRUE(tag.Type() == TagDataType::INVALID);
154 EXPECT_TRUE(tag.IsNull());
155 EXPECT_TRUE(tag.Typename() == "none");
156
157 EXPECT_FALSE(tag.IsNumeric());
158 EXPECT_FALSE(tag.IsString());
159 EXPECT_FALSE(tag.IsArray());
160 }
161
TEST(TagTest,Type_Int8)162 TEST(TagTest, Type_Int8)
163 {
164 const int8_t v = -42;
165 const Tag tag(v);
166
167 int8_t v2{};
168 EXPECT_NO_THROW(v2 = tag.ToInt8());
169
170 EXPECT_TRUE(tag.Type() == TagDataType::INT8);
171 EXPECT_TRUE(tag.Typename() == "int8_t");
172 EXPECT_TRUE(tag.IsInt8());
173
174 EXPECT_TRUE(tag.IsSignedInt());
175 EXPECT_TRUE(tag.IsIntegral());
176 EXPECT_TRUE(tag.IsNumeric());
177
178 EXPECT_FALSE(tag.IsUnsignedInt());
179 EXPECT_FALSE(tag.IsNull());
180 EXPECT_FALSE(tag.IsFloat());
181 EXPECT_FALSE(tag.IsString());
182 EXPECT_FALSE(tag.IsArray());
183
184 EXPECT_EQ(v, v2);
185 }
186
TEST(TagTest,Type_UInt8)187 TEST(TagTest, Type_UInt8)
188 {
189 const uint8_t v = 42;
190 const Tag tag(v);
191
192 uint8_t v2{};
193 EXPECT_NO_THROW(v2 = tag.ToUInt8());
194
195 EXPECT_TRUE(tag.Type() == TagDataType::UINT8);
196 EXPECT_TRUE(tag.Typename() == "uint8_t");
197 EXPECT_TRUE(tag.IsUInt8());
198
199 EXPECT_TRUE(tag.IsUnsignedInt());
200 EXPECT_TRUE(tag.IsIntegral());
201 EXPECT_TRUE(tag.IsNumeric());
202
203 EXPECT_FALSE(tag.IsSignedInt());
204 EXPECT_FALSE(tag.IsNull());
205 EXPECT_FALSE(tag.IsFloat());
206 EXPECT_FALSE(tag.IsString());
207 EXPECT_FALSE(tag.IsArray());
208
209 EXPECT_EQ(v, v2);
210 }
211
TEST(TagTest,Type_Ascii)212 TEST(TagTest, Type_Ascii)
213 {
214 const char c = '$';
215 const signed char sc = '$';
216 const unsigned char uc = '$';
217 const uint8_t u8 = 65;
218 const int8_t i8 = 66;
219
220 { // old style: construct-then-modify
221
222 Tag fromPlainChar = Tag(c);
223 Tag fromSignedChar = Tag(sc);
224 Tag fromUnsignedChar = Tag(uc);
225 Tag fromUint8 = Tag(u8);
226 Tag fromInt8 = Tag(i8);
227 fromPlainChar.Modifier(TagModifier::ASCII_CHAR);
228 fromSignedChar.Modifier(TagModifier::ASCII_CHAR);
229 fromUnsignedChar.Modifier(TagModifier::ASCII_CHAR);
230 fromUint8.Modifier(TagModifier::ASCII_CHAR);
231 fromInt8.Modifier(TagModifier::ASCII_CHAR);
232
233 EXPECT_TRUE(fromPlainChar.HasModifier(TagModifier::ASCII_CHAR));
234 EXPECT_TRUE(fromPlainChar.IsIntegral());
235 EXPECT_TRUE(fromPlainChar.IsNumeric());
236 EXPECT_EQ('$', fromPlainChar.ToAscii());
237
238 EXPECT_TRUE(fromSignedChar.HasModifier(TagModifier::ASCII_CHAR));
239 EXPECT_TRUE(fromSignedChar.IsIntegral());
240 EXPECT_TRUE(fromSignedChar.IsNumeric());
241 EXPECT_EQ('$', fromSignedChar.ToAscii());
242
243 EXPECT_TRUE(fromUnsignedChar.HasModifier(TagModifier::ASCII_CHAR));
244 EXPECT_TRUE(fromUnsignedChar.IsIntegral());
245 EXPECT_TRUE(fromUnsignedChar.IsNumeric());
246 EXPECT_EQ('$', fromUnsignedChar.ToAscii());
247
248 EXPECT_TRUE(fromUint8.HasModifier(TagModifier::ASCII_CHAR));
249 EXPECT_TRUE(fromUint8.IsIntegral());
250 EXPECT_TRUE(fromUint8.IsNumeric());
251 EXPECT_EQ('A', fromUint8.ToAscii());
252
253 EXPECT_TRUE(fromInt8.HasModifier(TagModifier::ASCII_CHAR));
254 EXPECT_TRUE(fromInt8.IsIntegral());
255 EXPECT_TRUE(fromInt8.IsNumeric());
256 EXPECT_EQ('B', fromInt8.ToAscii());
257 }
258
259 { // new style: construct directly as ASCII
260
261 const Tag fromPlainChar = Tag(c, TagModifier::ASCII_CHAR);
262 const Tag fromSignedChar = Tag(sc, TagModifier::ASCII_CHAR);
263 const Tag fromUnsignedChar = Tag(uc, TagModifier::ASCII_CHAR);
264 const Tag fromUint8 = Tag(u8, TagModifier::ASCII_CHAR);
265 const Tag fromInt8 = Tag(i8, TagModifier::ASCII_CHAR);
266
267 EXPECT_TRUE(fromPlainChar.HasModifier(TagModifier::ASCII_CHAR));
268 EXPECT_TRUE(fromPlainChar.IsIntegral());
269 EXPECT_TRUE(fromPlainChar.IsNumeric());
270 EXPECT_EQ('$', fromPlainChar.ToAscii());
271
272 EXPECT_TRUE(fromSignedChar.HasModifier(TagModifier::ASCII_CHAR));
273 EXPECT_TRUE(fromSignedChar.IsIntegral());
274 EXPECT_TRUE(fromSignedChar.IsNumeric());
275 EXPECT_EQ('$', fromSignedChar.ToAscii());
276
277 EXPECT_TRUE(fromUnsignedChar.HasModifier(TagModifier::ASCII_CHAR));
278 EXPECT_TRUE(fromUnsignedChar.IsIntegral());
279 EXPECT_TRUE(fromUnsignedChar.IsNumeric());
280 EXPECT_EQ('$', fromUnsignedChar.ToAscii());
281
282 EXPECT_TRUE(fromUint8.HasModifier(TagModifier::ASCII_CHAR));
283 EXPECT_TRUE(fromUint8.IsIntegral());
284 EXPECT_TRUE(fromUint8.IsNumeric());
285 EXPECT_EQ('A', fromUint8.ToAscii());
286
287 EXPECT_TRUE(fromInt8.HasModifier(TagModifier::ASCII_CHAR));
288 EXPECT_TRUE(fromInt8.IsIntegral());
289 EXPECT_TRUE(fromInt8.IsNumeric());
290 EXPECT_EQ('B', fromInt8.ToAscii());
291 }
292
293 // check invalid constructs
294 EXPECT_THROW(Tag('A', TagModifier::HEX_STRING), std::runtime_error);
295 }
296
TEST(TagTest,Type_Int16)297 TEST(TagTest, Type_Int16)
298 {
299 const int16_t v = -42;
300 const Tag tag(v);
301
302 int16_t v2{};
303 EXPECT_NO_THROW(v2 = tag.ToInt16());
304
305 EXPECT_TRUE(tag.Type() == TagDataType::INT16);
306 EXPECT_TRUE(tag.Typename() == "int16_t");
307 EXPECT_TRUE(tag.IsInt16());
308 EXPECT_TRUE(tag.IsSignedInt());
309 EXPECT_TRUE(tag.IsIntegral());
310 EXPECT_TRUE(tag.IsNumeric());
311
312 EXPECT_FALSE(tag.IsUnsignedInt());
313 EXPECT_FALSE(tag.IsNull());
314 EXPECT_FALSE(tag.IsFloat());
315 EXPECT_FALSE(tag.IsString());
316 EXPECT_FALSE(tag.IsArray());
317
318 EXPECT_EQ(v, v2);
319 }
320
TEST(TagTest,Type_UInt16)321 TEST(TagTest, Type_UInt16)
322 {
323 const uint16_t v = 42;
324 const Tag tag(v);
325
326 uint16_t v2;
327 EXPECT_NO_THROW(v2 = tag.ToUInt16());
328
329 EXPECT_TRUE(tag.Type() == TagDataType::UINT16);
330 EXPECT_TRUE(tag.Typename() == "uint16_t");
331 EXPECT_TRUE(tag.IsUInt16());
332 EXPECT_TRUE(tag.IsUnsignedInt());
333 EXPECT_TRUE(tag.IsIntegral());
334 EXPECT_TRUE(tag.IsNumeric());
335
336 EXPECT_FALSE(tag.IsSignedInt());
337 EXPECT_FALSE(tag.IsNull());
338 EXPECT_FALSE(tag.IsFloat());
339 EXPECT_FALSE(tag.IsString());
340 EXPECT_FALSE(tag.IsArray());
341
342 EXPECT_EQ(v, v2);
343 }
344
TEST(TagTest,Type_Int32)345 TEST(TagTest, Type_Int32)
346 {
347 const int32_t v = -42;
348 const Tag tag(v);
349
350 int32_t v2;
351 EXPECT_NO_THROW(v2 = tag.ToInt32());
352
353 EXPECT_TRUE(tag.Type() == TagDataType::INT32);
354 EXPECT_TRUE(tag.Typename() == "int32_t");
355 EXPECT_TRUE(tag.IsInt32());
356 EXPECT_TRUE(tag.IsSignedInt());
357 EXPECT_TRUE(tag.IsIntegral());
358 EXPECT_TRUE(tag.IsNumeric());
359
360 EXPECT_FALSE(tag.IsUnsignedInt());
361 EXPECT_FALSE(tag.IsNull());
362 EXPECT_FALSE(tag.IsFloat());
363 EXPECT_FALSE(tag.IsString());
364 EXPECT_FALSE(tag.IsArray());
365
366 EXPECT_EQ(v, v2);
367 }
368
TEST(TagTest,Type_UInt32)369 TEST(TagTest, Type_UInt32)
370 {
371 const uint32_t v = 42;
372 const Tag tag(v);
373
374 uint32_t v2;
375 EXPECT_NO_THROW(v2 = tag.ToUInt32());
376
377 EXPECT_TRUE(tag.Type() == TagDataType::UINT32);
378 EXPECT_TRUE(tag.Typename() == "uint32_t");
379 EXPECT_TRUE(tag.IsUInt32());
380 EXPECT_TRUE(tag.IsUnsignedInt());
381 EXPECT_TRUE(tag.IsIntegral());
382 EXPECT_TRUE(tag.IsNumeric());
383
384 EXPECT_FALSE(tag.IsSignedInt());
385 EXPECT_FALSE(tag.IsNull());
386 EXPECT_FALSE(tag.IsFloat());
387 EXPECT_FALSE(tag.IsString());
388 EXPECT_FALSE(tag.IsArray());
389
390 EXPECT_EQ(v, v2);
391 }
392
TEST(TagTest,Type_Float)393 TEST(TagTest, Type_Float)
394 {
395 const float v = 3.141;
396 const Tag tag(v);
397
398 float v2;
399 EXPECT_NO_THROW(v2 = tag.ToFloat());
400
401 EXPECT_TRUE(tag.Type() == TagDataType::FLOAT);
402 EXPECT_TRUE(tag.Typename() == "float");
403 EXPECT_TRUE(tag.IsFloat());
404 EXPECT_TRUE(tag.IsNumeric());
405
406 EXPECT_FALSE(tag.IsNull());
407 EXPECT_FALSE(tag.IsIntegral());
408 EXPECT_FALSE(tag.IsString());
409 EXPECT_FALSE(tag.IsArray());
410
411 EXPECT_EQ(v, v2);
412 }
413
TEST(TagTest,Type_String)414 TEST(TagTest, Type_String)
415 {
416 const std::string v = "foo_who";
417 const Tag tag(v);
418
419 std::string v2;
420 EXPECT_NO_THROW(v2 = tag.ToString());
421
422 EXPECT_TRUE(tag.Type() == TagDataType::STRING);
423 EXPECT_TRUE(tag.Typename() == "string");
424 EXPECT_TRUE(tag.IsString());
425
426 EXPECT_FALSE(tag.IsNull());
427 EXPECT_FALSE(tag.IsNumeric());
428 EXPECT_FALSE(tag.IsArray());
429
430 EXPECT_EQ(v, v2);
431
432 // "Hex format" string
433 const Tag hex("DEADBEEF", TagModifier::HEX_STRING);
434 EXPECT_TRUE(hex.Type() == TagDataType::STRING);
435 EXPECT_TRUE(hex.Typename() == "string");
436 EXPECT_TRUE(hex.IsString());
437 EXPECT_TRUE(hex.HasModifier(TagModifier::HEX_STRING));
438 EXPECT_FALSE(hex.IsNull());
439 EXPECT_FALSE(hex.IsNumeric());
440 EXPECT_FALSE(hex.IsArray());
441
442 // check invalid constructs
443 EXPECT_THROW(Tag("DEADBEEF", TagModifier::ASCII_CHAR), std::runtime_error);
444 }
445
TEST(TagTest,Type_Int8Array)446 TEST(TagTest, Type_Int8Array)
447 {
448 const std::vector<int8_t> v = {-42, 100, 0};
449 const Tag tag(v);
450
451 std::vector<int8_t> v2;
452 EXPECT_NO_THROW(v2 = tag.ToInt8Array());
453
454 EXPECT_TRUE(tag.Type() == TagDataType::INT8_ARRAY);
455 EXPECT_TRUE(tag.Typename() == "vector<int8_t>");
456 EXPECT_TRUE(tag.IsInt8Array());
457 EXPECT_TRUE(tag.IsSignedArray());
458 EXPECT_TRUE(tag.IsIntegralArray());
459 EXPECT_TRUE(tag.IsArray());
460
461 EXPECT_FALSE(tag.IsFloat());
462 EXPECT_FALSE(tag.IsString());
463 EXPECT_FALSE(tag.IsNull());
464 EXPECT_FALSE(tag.IsNumeric());
465
466 EXPECT_EQ(v, v2);
467 }
468
TEST(TagTest,Type_UInt8Array)469 TEST(TagTest, Type_UInt8Array)
470 {
471 const std::vector<uint8_t> v = {42, 200, 0};
472 const Tag tag(v);
473
474 std::vector<uint8_t> v2;
475 EXPECT_NO_THROW(v2 = tag.ToUInt8Array());
476
477 EXPECT_TRUE(tag.Type() == TagDataType::UINT8_ARRAY);
478 EXPECT_TRUE(tag.Typename() == "vector<uint8_t>");
479 EXPECT_TRUE(tag.IsUInt8Array());
480 EXPECT_TRUE(tag.IsUnsignedArray());
481 EXPECT_TRUE(tag.IsIntegralArray());
482 EXPECT_TRUE(tag.IsArray());
483
484 EXPECT_FALSE(tag.IsFloat());
485 EXPECT_FALSE(tag.IsString());
486 EXPECT_FALSE(tag.IsNull());
487 EXPECT_FALSE(tag.IsNumeric());
488
489 EXPECT_EQ(v, v2);
490 }
491
TEST(TagTest,Type_Int16Array)492 TEST(TagTest, Type_Int16Array)
493 {
494 const std::vector<int16_t> v = {42, -300, 0};
495 const Tag tag(v);
496
497 std::vector<int16_t> v2;
498 EXPECT_NO_THROW(v2 = tag.ToInt16Array());
499
500 EXPECT_TRUE(tag.Type() == TagDataType::INT16_ARRAY);
501 EXPECT_TRUE(tag.Typename() == "vector<int16_t>");
502 EXPECT_TRUE(tag.IsInt16Array());
503 EXPECT_TRUE(tag.IsSignedArray());
504 EXPECT_TRUE(tag.IsIntegralArray());
505 EXPECT_TRUE(tag.IsArray());
506
507 EXPECT_FALSE(tag.IsFloat());
508 EXPECT_FALSE(tag.IsString());
509 EXPECT_FALSE(tag.IsNull());
510 EXPECT_FALSE(tag.IsNumeric());
511
512 EXPECT_EQ(v, v2);
513 }
514
TEST(TagTest,Type_UInt16Array)515 TEST(TagTest, Type_UInt16Array)
516 {
517 const std::vector<uint16_t> v = {42, 300, 0};
518 const Tag tag(v);
519
520 std::vector<uint16_t> v2;
521 EXPECT_NO_THROW(v2 = tag.ToUInt16Array());
522
523 EXPECT_TRUE(tag.Type() == TagDataType::UINT16_ARRAY);
524 EXPECT_TRUE(tag.Typename() == "vector<uint16_t>");
525 EXPECT_TRUE(tag.IsUInt16Array());
526 EXPECT_TRUE(tag.IsUnsignedArray());
527 EXPECT_TRUE(tag.IsIntegralArray());
528 EXPECT_TRUE(tag.IsArray());
529
530 EXPECT_FALSE(tag.IsFloat());
531 EXPECT_FALSE(tag.IsString());
532 EXPECT_FALSE(tag.IsNull());
533 EXPECT_FALSE(tag.IsNumeric());
534
535 EXPECT_EQ(v, v2);
536 ;
537 }
538
TEST(TagTest,Type_Int32Array)539 TEST(TagTest, Type_Int32Array)
540 {
541 const std::vector<int32_t> v = {42, -300, 0};
542 const Tag tag(v);
543
544 std::vector<int32_t> v2;
545 EXPECT_NO_THROW(v2 = tag.ToInt32Array());
546
547 EXPECT_TRUE(tag.Type() == TagDataType::INT32_ARRAY);
548 EXPECT_TRUE(tag.Typename() == "vector<int32_t>");
549 EXPECT_TRUE(tag.IsInt32Array());
550 EXPECT_TRUE(tag.IsSignedArray());
551 EXPECT_TRUE(tag.IsIntegralArray());
552 EXPECT_TRUE(tag.IsArray());
553
554 EXPECT_FALSE(tag.IsFloat());
555 EXPECT_FALSE(tag.IsString());
556 EXPECT_FALSE(tag.IsNull());
557 EXPECT_FALSE(tag.IsNumeric());
558
559 EXPECT_EQ(v, v2);
560 }
561
TEST(TagTest,Type_UInt32Array)562 TEST(TagTest, Type_UInt32Array)
563 {
564 const std::vector<uint32_t> v = {42, 300, 0};
565 const Tag tag(v);
566
567 std::vector<uint32_t> v2;
568 EXPECT_NO_THROW(v2 = tag.ToUInt32Array());
569
570 EXPECT_TRUE(tag.Type() == TagDataType::UINT32_ARRAY);
571 EXPECT_TRUE(tag.Typename() == "vector<uint32_t>");
572 EXPECT_TRUE(tag.IsUInt32Array());
573 EXPECT_TRUE(tag.IsUnsignedArray());
574 EXPECT_TRUE(tag.IsIntegralArray());
575 EXPECT_TRUE(tag.IsArray());
576
577 EXPECT_FALSE(tag.IsFloat());
578 EXPECT_FALSE(tag.IsString());
579 EXPECT_FALSE(tag.IsNull());
580 EXPECT_FALSE(tag.IsNumeric());
581
582 EXPECT_EQ(v, v2);
583 }
584
TEST(TagTest,Type_FloatArray)585 TEST(TagTest, Type_FloatArray)
586 {
587 const std::vector<float> v = {1.1f, 1.2f, 1.3f};
588 const Tag tag(v);
589
590 std::vector<float> v2;
591 EXPECT_NO_THROW(v2 = tag.ToFloatArray());
592
593 EXPECT_TRUE(tag.Type() == TagDataType::FLOAT_ARRAY);
594 EXPECT_TRUE(tag.Typename() == "vector<float>");
595 EXPECT_TRUE(tag.IsFloatArray());
596 EXPECT_TRUE(tag.IsArray());
597
598 EXPECT_FALSE(tag.IsIntegralArray());
599 EXPECT_FALSE(tag.IsFloat());
600 EXPECT_FALSE(tag.IsString());
601 EXPECT_FALSE(tag.IsNull());
602 EXPECT_FALSE(tag.IsNumeric());
603
604 EXPECT_EQ(v, v2);
605 }
606
TEST(TagTest,CastBackToOriginalOk)607 TEST(TagTest, CastBackToOriginalOk)
608 {
609 int8_t i8 = 0;
610 uint8_t u8 = 0;
611 int16_t i16 = 0;
612 uint16_t u16 = 0;
613 int32_t i32 = 0;
614 uint32_t u32 = 0;
615 float f = 0.0;
616 std::string str = "";
617 std::vector<int8_t> i8_array;
618 std::vector<uint8_t> u8_array;
619 std::vector<int16_t> i16_array;
620 std::vector<uint16_t> u16_array;
621 std::vector<int32_t> i32_array;
622 std::vector<uint32_t> u32_array;
623 std::vector<float> float_array;
624
625 Tag i8Tag(i8);
626 Tag u8Tag(u8);
627 Tag i16Tag(i16);
628 Tag u16Tag(u16);
629 Tag i32Tag(i32);
630 Tag u32Tag(u32);
631 Tag floatTag(f);
632 Tag stringTag(str);
633 Tag i8_array_Tag(i8_array);
634 Tag u8_array_Tag(u8_array);
635 Tag i16_array_Tag(i16_array);
636 Tag u16_array_Tag(u16_array);
637 Tag i32_array_Tag(i32_array);
638 Tag u32_array_Tag(u32_array);
639 Tag float_array_Tag(float_array);
640
641 EXPECT_NO_THROW({
642 i8 = i8Tag.ToInt8();
643 u8 = u8Tag.ToUInt8();
644 i16 = i16Tag.ToInt16();
645 u16 = u16Tag.ToUInt16();
646 i32 = i32Tag.ToInt32();
647 u32 = u32Tag.ToUInt32();
648 f = floatTag.ToFloat();
649 str = stringTag.ToString();
650 i8_array = i8_array_Tag.ToInt8Array();
651 u8_array = u8_array_Tag.ToUInt8Array();
652 i16_array = i16_array_Tag.ToInt16Array();
653 u16_array = u16_array_Tag.ToUInt16Array();
654 i32_array = i32_array_Tag.ToInt32Array();
655 u32_array = u32_array_Tag.ToUInt32Array();
656 float_array = float_array_Tag.ToFloatArray();
657 });
658 }
659
TEST(TagTest,ConvertToInt8)660 TEST(TagTest, ConvertToInt8)
661 {
662 Tag zero(int32_t{0});
663 Tag min(int32_t{std::numeric_limits<int8_t>::min()});
664 Tag normal(int32_t{42});
665 Tag max(int32_t{std::numeric_limits<int8_t>::max()});
666 Tag floatTag(float{3.14});
667 Tag stringTag(std::string{"foo"});
668 Tag arrayTag(std::vector<int8_t>{{1, 2, 3}});
669
670 // allowed
671 EXPECT_NO_THROW({
672 zero.ToInt8();
673 min.ToInt8();
674 normal.ToInt8();
675 max.ToInt8();
676 });
677
678 // not allowed
679 EXPECT_THROW(floatTag.ToInt8(), std::exception);
680 EXPECT_THROW(stringTag.ToInt8(), std::exception);
681 EXPECT_THROW(arrayTag.ToInt8(), std::exception);
682 }
683
TEST(TagTest,ConvertToUInt8)684 TEST(TagTest, ConvertToUInt8)
685 {
686 Tag zero(int32_t{0});
687 Tag neg(int32_t{-1});
688 Tag normal(int32_t{42});
689 Tag max(int32_t{std::numeric_limits<uint8_t>::max()});
690 Tag floatTag(float{3.14});
691 Tag stringTag(std::string{"foo"});
692 Tag arrayTag(std::vector<uint8_t>{{1, 2, 3}});
693
694 // allowed
695 EXPECT_NO_THROW({
696 zero.ToUInt8();
697 normal.ToUInt8();
698 max.ToUInt8();
699 });
700
701 // not allowed
702 EXPECT_THROW(neg.ToUInt8(), std::exception);
703 EXPECT_THROW(floatTag.ToUInt8(), std::exception);
704 EXPECT_THROW(stringTag.ToUInt8(), std::exception);
705 EXPECT_THROW(arrayTag.ToUInt8(), std::exception);
706 }
707
TEST(TagTest,ConvertToInt16)708 TEST(TagTest, ConvertToInt16)
709 {
710 Tag zero(int32_t{0});
711 Tag min(int32_t{std::numeric_limits<int16_t>::min()});
712 Tag normal(int32_t{42});
713 Tag max(int32_t{std::numeric_limits<int16_t>::max()});
714 Tag floatTag(float{3.14});
715 Tag stringTag(std::string{"foo"});
716 Tag arrayTag(std::vector<int16_t>{{1, 2, 3}});
717
718 // allowed
719 EXPECT_NO_THROW({
720 zero.ToInt16();
721 min.ToInt16();
722 normal.ToInt16();
723 max.ToInt16();
724 });
725
726 // not allowed
727 EXPECT_THROW(floatTag.ToInt16(), std::exception);
728 EXPECT_THROW(stringTag.ToInt16(), std::exception);
729 EXPECT_THROW(arrayTag.ToInt16(), std::exception);
730 }
731
TEST(TagTest,ConvertToUInt16)732 TEST(TagTest, ConvertToUInt16)
733 {
734 Tag zero(int32_t{0});
735 Tag neg(int32_t{-1});
736 Tag normal(int32_t{42});
737 Tag max(int32_t{std::numeric_limits<uint16_t>::max()});
738 Tag floatTag(float{3.14});
739 Tag stringTag(std::string{"foo"});
740 Tag arrayTag(std::vector<uint16_t>{{1, 2, 3}});
741
742 // allowed
743 EXPECT_NO_THROW({
744 zero.ToUInt16();
745 normal.ToUInt16();
746 max.ToUInt16();
747 });
748
749 // not allowed
750 EXPECT_THROW(neg.ToUInt16(), std::exception);
751 EXPECT_THROW(floatTag.ToUInt16(), std::exception);
752 EXPECT_THROW(stringTag.ToUInt16(), std::exception);
753 EXPECT_THROW(arrayTag.ToUInt16(), std::exception);
754 }
755
TEST(TagTest,ConvertToInt32)756 TEST(TagTest, ConvertToInt32)
757 {
758 Tag zero(int32_t{0});
759 Tag min(int32_t{std::numeric_limits<int32_t>::min()});
760 Tag normal(int32_t{42});
761 Tag max(int32_t{std::numeric_limits<int32_t>::max()});
762 Tag floatTag(float{3.14});
763 Tag stringTag(std::string{"foo"});
764 Tag arrayTag(std::vector<int32_t>{{1, 2, 3}});
765
766 // allowed
767 EXPECT_NO_THROW({
768 zero.ToInt32();
769 min.ToInt32();
770 normal.ToInt32();
771 max.ToInt32();
772 });
773
774 // not allowed
775 EXPECT_THROW(floatTag.ToInt32(), std::exception);
776 EXPECT_THROW(stringTag.ToInt32(), std::exception);
777 EXPECT_THROW(arrayTag.ToInt32(), std::exception);
778 }
779
TEST(TagTest,ConvertToUInt32)780 TEST(TagTest, ConvertToUInt32)
781 {
782 Tag zero(int32_t{0});
783 Tag neg(int32_t{-1});
784 Tag normal(int32_t{42});
785 Tag max(uint32_t{std::numeric_limits<uint32_t>::max()});
786 Tag floatTag(float{3.14});
787 Tag stringTag(std::string{"foo"});
788 Tag arrayTag(std::vector<uint32_t>{{1, 2, 3}});
789
790 // allowed
791 EXPECT_NO_THROW({
792 zero.ToUInt32();
793 normal.ToUInt32();
794 max.ToUInt32();
795 });
796
797 // not allowed
798 EXPECT_THROW(neg.ToUInt32(), std::exception);
799 EXPECT_THROW(floatTag.ToUInt32(), std::exception);
800 EXPECT_THROW(stringTag.ToUInt32(), std::exception);
801 EXPECT_THROW(arrayTag.ToUInt32(), std::exception);
802 }
803
TEST(TagCollectionTest,DefaultConstruction)804 TEST(TagCollectionTest, DefaultConstruction)
805 {
806 TagCollection tags;
807 EXPECT_TRUE(tags.empty());
808 EXPECT_FALSE(tags.Contains("XY"));
809 }
810
TEST(TagCollectionTest,AddSimpleTags)811 TEST(TagCollectionTest, AddSimpleTags)
812 {
813 const int32_t intValue = -42;
814 const std::string strValue = "foo";
815 const std::string hexStrValue = "1abc75";
816
817 TagCollection tags;
818 tags["ST"] = strValue;
819 tags["XY"] = intValue;
820 tags["HX"] = hexStrValue;
821 tags["HX"].Modifier(TagModifier::HEX_STRING);
822
823 EXPECT_EQ(3, tags.size());
824 EXPECT_TRUE(tags.Contains("XY"));
825 EXPECT_TRUE(tags.Contains("ST"));
826 EXPECT_TRUE(tags.Contains("HX"));
827 EXPECT_FALSE(tags.Contains("ZZ"));
828
829 EXPECT_TRUE(tags["XY"].ToInt32() == intValue);
830 EXPECT_TRUE(tags["ST"].ToString() == strValue);
831 EXPECT_TRUE(tags["HX"].ToString() == hexStrValue);
832 EXPECT_TRUE(tags["HX"].HasModifier(TagModifier::HEX_STRING));
833 }
834
TEST(SamTagCodecTest,DecodeTest)835 TEST(SamTagCodecTest, DecodeTest)
836 {
837 std::string tagString;
838 tagString.append("HX:H:1abc75");
839 tagString.append("\t");
840 tagString.append("ST:Z:foo");
841 tagString.append("\t");
842 tagString.append("VC:B:i,42,-100,37,2048");
843 tagString.append("\t");
844 tagString.append("XY:i:-42");
845
846 TagCollection expected;
847 expected["ST"] = std::string("foo");
848 expected["XY"] = int32_t{-42};
849 expected["HX"] = Tag("1abc75", TagModifier::HEX_STRING);
850 expected["VC"] = std::vector<int32_t>({42, -100, 37, 2048});
851
852 TagCollection tags = SamTagCodec::Decode(tagString);
853
854 EXPECT_TRUE(tags.Contains("ST"));
855 EXPECT_TRUE(tags.Contains("HX"));
856 EXPECT_TRUE(tags.Contains("XY"));
857 EXPECT_TRUE(tags.Contains("VC"));
858
859 EXPECT_EQ(std::string("foo"), tags["ST"].ToString());
860 EXPECT_TRUE(tags["HX"].HasModifier(TagModifier::HEX_STRING));
861 EXPECT_EQ(std::string("1abc75"), tags["HX"].ToString());
862 EXPECT_EQ(int8_t{-42}, tags["XY"].ToInt8());
863 EXPECT_EQ(std::vector<int32_t>({42, -100, 37, 2048}), tags["VC"].ToInt32Array());
864 }
865
TEST(SamTagCodecTest,EncodeTest)866 TEST(SamTagCodecTest, EncodeTest)
867 {
868 TagCollection tags;
869 tags["ST"] = std::string("foo");
870 tags["XY"] = int32_t{-42};
871 tags["HX"] = Tag("1abc75", TagModifier::HEX_STRING);
872 tags["VC"] = std::vector<int32_t>({42, -100, 37, 2048});
873
874 // "HX:H:1abc75\tST:Z:foo\0\tVC:B:i,42,-100,37,2048\tXY:i:-42"
875 std::string expected;
876 expected.append("HX:H:1abc75");
877 expected.append("\t");
878 expected.append("ST:Z:foo");
879 expected.append("\t");
880 expected.append("VC:B:i,42,-100,37,2048");
881 expected.append("\t");
882 expected.append("XY:i:-42");
883
884 const std::string sam = SamTagCodec::Encode(tags);
885 EXPECT_EQ(expected, sam);
886 }
887
TEST(BamTagCodecTest,DecodeTest)888 TEST(BamTagCodecTest, DecodeTest)
889 {
890 std::vector<uint8_t> data;
891 data.push_back(uint8_t('H'));
892 data.push_back(uint8_t('X'));
893 data.push_back(uint8_t('H'));
894 data.push_back(uint8_t('1'));
895 data.push_back(uint8_t('a'));
896 data.push_back(uint8_t('b'));
897 data.push_back(uint8_t('c'));
898 data.push_back(uint8_t('7'));
899 data.push_back(uint8_t('5'));
900 data.push_back(uint8_t(0));
901
902 data.push_back(uint8_t('X'));
903 data.push_back(uint8_t('Y'));
904 data.push_back(uint8_t('i'));
905 const int32_t x = -42;
906 char valueBytes[sizeof x];
907 std::copy(static_cast<const char*>(static_cast<const void*>(&x)),
908 static_cast<const char*>(static_cast<const void*>(&x)) + sizeof x, valueBytes);
909 data.push_back(valueBytes[0]);
910 data.push_back(valueBytes[1]);
911 data.push_back(valueBytes[2]);
912 data.push_back(valueBytes[3]);
913
914 data.push_back('C');
915 data.push_back('A');
916 data.push_back('B');
917 data.push_back('C');
918 const uint32_t numChars = 3;
919 char numCharsValueBytes[sizeof numChars];
920 std::copy(static_cast<const char*>(static_cast<const void*>(&numChars)),
921 static_cast<const char*>(static_cast<const void*>(&numChars)) + sizeof numChars,
922 numCharsValueBytes);
923 data.push_back(numCharsValueBytes[0]);
924 data.push_back(numCharsValueBytes[1]);
925 data.push_back(numCharsValueBytes[2]);
926 data.push_back(numCharsValueBytes[3]);
927
928 const std::vector<uint8_t> charArray = std::vector<uint8_t>({34, 5, 125});
929 data.push_back(charArray.at(0));
930 data.push_back(charArray.at(1));
931 data.push_back(charArray.at(2));
932
933 TagCollection tags = BamTagCodec::Decode(data);
934
935 EXPECT_TRUE(tags["HX"].HasModifier(TagModifier::HEX_STRING));
936 EXPECT_EQ(std::string("1abc75"), tags["HX"].ToString());
937 EXPECT_EQ(x, tags["XY"].ToInt32());
938 EXPECT_EQ(charArray, tags["CA"].ToUInt8Array());
939
940 // sanity check - convert tags back to SAM
941 std::string expected;
942 expected.append("CA:B:C,34,5,125");
943 expected.append("\t");
944 expected.append("HX:H:1abc75");
945 expected.append("\t");
946 expected.append("XY:i:-42");
947
948 const std::string sam = SamTagCodec::Encode(tags);
949 EXPECT_EQ(expected, sam);
950 }
951
TEST(BamTagCodecTest,EncodeTest)952 TEST(BamTagCodecTest, EncodeTest)
953 {
954 std::vector<uint8_t> expected;
955
956 expected.push_back('C');
957 expected.push_back('A');
958 expected.push_back('B');
959 expected.push_back('C');
960 const uint32_t numChars = 3;
961 char numCharsValueBytes[sizeof numChars];
962 std::copy(static_cast<const char*>(static_cast<const void*>(&numChars)),
963 static_cast<const char*>(static_cast<const void*>(&numChars)) + sizeof numChars,
964 numCharsValueBytes);
965 expected.push_back(numCharsValueBytes[0]);
966 expected.push_back(numCharsValueBytes[1]);
967 expected.push_back(numCharsValueBytes[2]);
968 expected.push_back(numCharsValueBytes[3]);
969
970 const std::vector<uint8_t> charArray = std::vector<uint8_t>({34, 5, 125});
971 expected.push_back(charArray.at(0));
972 expected.push_back(charArray.at(1));
973 expected.push_back(charArray.at(2));
974
975 expected.push_back(uint8_t('H'));
976 expected.push_back(uint8_t('X'));
977 expected.push_back(uint8_t('H'));
978 expected.push_back(uint8_t('1'));
979 expected.push_back(uint8_t('a'));
980 expected.push_back(uint8_t('b'));
981 expected.push_back(uint8_t('c'));
982 expected.push_back(uint8_t('7'));
983 expected.push_back(uint8_t('5'));
984 expected.push_back(uint8_t(0));
985
986 expected.push_back(uint8_t('X'));
987 expected.push_back(uint8_t('Y'));
988 expected.push_back(uint8_t('i'));
989 const int32_t x = -42;
990 char valueBytes[sizeof x];
991 std::copy(static_cast<const char*>(static_cast<const void*>(&x)),
992 static_cast<const char*>(static_cast<const void*>(&x)) + sizeof x, valueBytes);
993 expected.push_back(valueBytes[0]);
994 expected.push_back(valueBytes[1]);
995 expected.push_back(valueBytes[2]);
996 expected.push_back(valueBytes[3]);
997
998 TagCollection tags;
999 tags["HX"] = Tag("1abc75", TagModifier::HEX_STRING);
1000 tags["CA"] = charArray;
1001 tags["XY"] = x;
1002
1003 const std::vector<uint8_t> data = BamTagCodec::Encode(tags);
1004 EXPECT_EQ(expected, data);
1005 }
1006
TEST(BamTagCodecTest,AsciiTagsTest)1007 TEST(BamTagCodecTest, AsciiTagsTest)
1008 {
1009 std::vector<uint8_t> expected;
1010 expected.reserve(20);
1011 expected.push_back('I'); // I8:A:B
1012 expected.push_back('8');
1013 expected.push_back('A');
1014 expected.push_back('B');
1015 expected.push_back('P'); // PC:A:$
1016 expected.push_back('C');
1017 expected.push_back('A');
1018 expected.push_back('$');
1019 expected.push_back('S'); // SC:A:$
1020 expected.push_back('C');
1021 expected.push_back('A');
1022 expected.push_back('$');
1023 expected.push_back('U'); // U8:A:A
1024 expected.push_back('8');
1025 expected.push_back('A');
1026 expected.push_back('A');
1027 expected.push_back('U'); // UC:A:$
1028 expected.push_back('C');
1029 expected.push_back('A');
1030 expected.push_back('$');
1031
1032 const char c = '$';
1033 const signed char sc = '$';
1034 const unsigned char uc = '$';
1035 const uint8_t u8 = 65;
1036 const int8_t i8 = 66;
1037
1038 { // old style: construct-then-modify
1039
1040 Tag fromPlainChar = Tag(c);
1041 Tag fromSignedChar = Tag(sc);
1042 Tag fromUnsignedChar = Tag(uc);
1043 Tag fromUint8 = Tag(u8);
1044 Tag fromInt8 = Tag(i8);
1045 fromPlainChar.Modifier(TagModifier::ASCII_CHAR);
1046 fromSignedChar.Modifier(TagModifier::ASCII_CHAR);
1047 fromUnsignedChar.Modifier(TagModifier::ASCII_CHAR);
1048 fromUint8.Modifier(TagModifier::ASCII_CHAR);
1049 fromInt8.Modifier(TagModifier::ASCII_CHAR);
1050
1051 TagCollection tags;
1052 tags["PC"] = fromPlainChar;
1053 tags["SC"] = fromSignedChar;
1054 tags["UC"] = fromUnsignedChar;
1055 tags["U8"] = fromUint8;
1056 tags["I8"] = fromInt8;
1057
1058 const std::vector<uint8_t> data = BamTagCodec::Encode(tags);
1059 EXPECT_EQ(expected, data);
1060 }
1061
1062 { // new style: construct directly as ASCII
1063
1064 const Tag fromPlainChar = Tag(c, TagModifier::ASCII_CHAR);
1065 const Tag fromSignedChar = Tag(sc, TagModifier::ASCII_CHAR);
1066 const Tag fromUnsignedChar = Tag(uc, TagModifier::ASCII_CHAR);
1067 const Tag fromUint8 = Tag(u8, TagModifier::ASCII_CHAR);
1068 const Tag fromInt8 = Tag(i8, TagModifier::ASCII_CHAR);
1069
1070 TagCollection tags;
1071 tags["PC"] = fromPlainChar;
1072 tags["SC"] = fromSignedChar;
1073 tags["UC"] = fromUnsignedChar;
1074 tags["U8"] = fromUint8;
1075 tags["I8"] = fromInt8;
1076
1077 const std::vector<uint8_t> data = BamTagCodec::Encode(tags);
1078 EXPECT_EQ(expected, data);
1079 }
1080 }
1081