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