1 //===- unittest/Support/YAMLIOTest.cpp ------------------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "llvm/ADT/Twine.h"
11 #include "llvm/Support/Casting.h"
12 #include "llvm/Support/Endian.h"
13 #include "llvm/Support/Format.h"
14 #include "llvm/Support/YAMLTraits.h"
15 #include "gtest/gtest.h"
16 
17 
18 using llvm::yaml::Input;
19 using llvm::yaml::Output;
20 using llvm::yaml::IO;
21 using llvm::yaml::MappingTraits;
22 using llvm::yaml::MappingNormalization;
23 using llvm::yaml::ScalarTraits;
24 using llvm::yaml::Hex8;
25 using llvm::yaml::Hex16;
26 using llvm::yaml::Hex32;
27 using llvm::yaml::Hex64;
28 
29 
30 
31 
suppressErrorMessages(const llvm::SMDiagnostic &,void *)32 static void suppressErrorMessages(const llvm::SMDiagnostic &, void *) {
33 }
34 
35 
36 
37 //===----------------------------------------------------------------------===//
38 //  Test MappingTraits
39 //===----------------------------------------------------------------------===//
40 
41 struct FooBar {
42   int foo;
43   int bar;
44 };
45 typedef std::vector<FooBar> FooBarSequence;
46 
47 LLVM_YAML_IS_SEQUENCE_VECTOR(FooBar)
48 
49 struct FooBarContainer {
50   FooBarSequence fbs;
51 };
52 
53 namespace llvm {
54 namespace yaml {
55   template <>
56   struct MappingTraits<FooBar> {
mappingllvm::yaml::MappingTraits57     static void mapping(IO &io, FooBar& fb) {
58       io.mapRequired("foo",    fb.foo);
59       io.mapRequired("bar",    fb.bar);
60     }
61   };
62 
63   template <> struct MappingTraits<FooBarContainer> {
mappingllvm::yaml::MappingTraits64     static void mapping(IO &io, FooBarContainer &fb) {
65       io.mapRequired("fbs", fb.fbs);
66     }
67   };
68 }
69 }
70 
71 
72 //
73 // Test the reading of a yaml mapping
74 //
TEST(YAMLIO,TestMapRead)75 TEST(YAMLIO, TestMapRead) {
76   FooBar doc;
77   {
78     Input yin("---\nfoo:  3\nbar:  5\n...\n");
79     yin >> doc;
80 
81     EXPECT_FALSE(yin.error());
82     EXPECT_EQ(doc.foo, 3);
83     EXPECT_EQ(doc.bar, 5);
84   }
85 
86   {
87     Input yin("{foo: 3, bar: 5}");
88     yin >> doc;
89 
90     EXPECT_FALSE(yin.error());
91     EXPECT_EQ(doc.foo, 3);
92     EXPECT_EQ(doc.bar, 5);
93   }
94 }
95 
TEST(YAMLIO,TestMalformedMapRead)96 TEST(YAMLIO, TestMalformedMapRead) {
97   FooBar doc;
98   Input yin("{foo: 3; bar: 5}", nullptr, suppressErrorMessages);
99   yin >> doc;
100   EXPECT_TRUE(!!yin.error());
101 }
102 
103 //
104 // Test the reading of a yaml sequence of mappings
105 //
TEST(YAMLIO,TestSequenceMapRead)106 TEST(YAMLIO, TestSequenceMapRead) {
107   FooBarSequence seq;
108   Input yin("---\n - foo:  3\n   bar:  5\n - foo:  7\n   bar:  9\n...\n");
109   yin >> seq;
110 
111   EXPECT_FALSE(yin.error());
112   EXPECT_EQ(seq.size(), 2UL);
113   FooBar& map1 = seq[0];
114   FooBar& map2 = seq[1];
115   EXPECT_EQ(map1.foo, 3);
116   EXPECT_EQ(map1.bar, 5);
117   EXPECT_EQ(map2.foo, 7);
118   EXPECT_EQ(map2.bar, 9);
119 }
120 
121 //
122 // Test the reading of a map containing a yaml sequence of mappings
123 //
TEST(YAMLIO,TestContainerSequenceMapRead)124 TEST(YAMLIO, TestContainerSequenceMapRead) {
125   {
126     FooBarContainer cont;
127     Input yin2("---\nfbs:\n - foo: 3\n   bar: 5\n - foo: 7\n   bar: 9\n...\n");
128     yin2 >> cont;
129 
130     EXPECT_FALSE(yin2.error());
131     EXPECT_EQ(cont.fbs.size(), 2UL);
132     EXPECT_EQ(cont.fbs[0].foo, 3);
133     EXPECT_EQ(cont.fbs[0].bar, 5);
134     EXPECT_EQ(cont.fbs[1].foo, 7);
135     EXPECT_EQ(cont.fbs[1].bar, 9);
136   }
137 
138   {
139     FooBarContainer cont;
140     Input yin("---\nfbs:\n...\n");
141     yin >> cont;
142     // Okay: Empty node represents an empty array.
143     EXPECT_FALSE(yin.error());
144     EXPECT_EQ(cont.fbs.size(), 0UL);
145   }
146 
147   {
148     FooBarContainer cont;
149     Input yin("---\nfbs: !!null null\n...\n");
150     yin >> cont;
151     // Okay: null represents an empty array.
152     EXPECT_FALSE(yin.error());
153     EXPECT_EQ(cont.fbs.size(), 0UL);
154   }
155 
156   {
157     FooBarContainer cont;
158     Input yin("---\nfbs: ~\n...\n");
159     yin >> cont;
160     // Okay: null represents an empty array.
161     EXPECT_FALSE(yin.error());
162     EXPECT_EQ(cont.fbs.size(), 0UL);
163   }
164 
165   {
166     FooBarContainer cont;
167     Input yin("---\nfbs: null\n...\n");
168     yin >> cont;
169     // Okay: null represents an empty array.
170     EXPECT_FALSE(yin.error());
171     EXPECT_EQ(cont.fbs.size(), 0UL);
172   }
173 }
174 
175 //
176 // Test the reading of a map containing a malformed yaml sequence
177 //
TEST(YAMLIO,TestMalformedContainerSequenceMapRead)178 TEST(YAMLIO, TestMalformedContainerSequenceMapRead) {
179   {
180     FooBarContainer cont;
181     Input yin("---\nfbs:\n   foo: 3\n   bar: 5\n...\n", nullptr,
182               suppressErrorMessages);
183     yin >> cont;
184     // Error: fbs is not a sequence.
185     EXPECT_TRUE(!!yin.error());
186     EXPECT_EQ(cont.fbs.size(), 0UL);
187   }
188 
189   {
190     FooBarContainer cont;
191     Input yin("---\nfbs: 'scalar'\n...\n", nullptr, suppressErrorMessages);
192     yin >> cont;
193     // This should be an error.
194     EXPECT_TRUE(!!yin.error());
195     EXPECT_EQ(cont.fbs.size(), 0UL);
196   }
197 }
198 
199 //
200 // Test writing then reading back a sequence of mappings
201 //
TEST(YAMLIO,TestSequenceMapWriteAndRead)202 TEST(YAMLIO, TestSequenceMapWriteAndRead) {
203   std::string intermediate;
204   {
205     FooBar entry1;
206     entry1.foo = 10;
207     entry1.bar = -3;
208     FooBar entry2;
209     entry2.foo = 257;
210     entry2.bar = 0;
211     FooBarSequence seq;
212     seq.push_back(entry1);
213     seq.push_back(entry2);
214 
215     llvm::raw_string_ostream ostr(intermediate);
216     Output yout(ostr);
217     yout << seq;
218   }
219 
220   {
221     Input yin(intermediate);
222     FooBarSequence seq2;
223     yin >> seq2;
224 
225     EXPECT_FALSE(yin.error());
226     EXPECT_EQ(seq2.size(), 2UL);
227     FooBar& map1 = seq2[0];
228     FooBar& map2 = seq2[1];
229     EXPECT_EQ(map1.foo, 10);
230     EXPECT_EQ(map1.bar, -3);
231     EXPECT_EQ(map2.foo, 257);
232     EXPECT_EQ(map2.bar, 0);
233   }
234 }
235 
236 
237 //===----------------------------------------------------------------------===//
238 //  Test built-in types
239 //===----------------------------------------------------------------------===//
240 
241 struct BuiltInTypes {
242   llvm::StringRef str;
243   std::string stdstr;
244   uint64_t        u64;
245   uint32_t        u32;
246   uint16_t        u16;
247   uint8_t         u8;
248   bool            b;
249   int64_t         s64;
250   int32_t         s32;
251   int16_t         s16;
252   int8_t          s8;
253   float           f;
254   double          d;
255   Hex8            h8;
256   Hex16           h16;
257   Hex32           h32;
258   Hex64           h64;
259 };
260 
261 namespace llvm {
262 namespace yaml {
263   template <>
264   struct MappingTraits<BuiltInTypes> {
mappingllvm::yaml::MappingTraits265     static void mapping(IO &io, BuiltInTypes& bt) {
266       io.mapRequired("str",      bt.str);
267       io.mapRequired("stdstr",   bt.stdstr);
268       io.mapRequired("u64",      bt.u64);
269       io.mapRequired("u32",      bt.u32);
270       io.mapRequired("u16",      bt.u16);
271       io.mapRequired("u8",       bt.u8);
272       io.mapRequired("b",        bt.b);
273       io.mapRequired("s64",      bt.s64);
274       io.mapRequired("s32",      bt.s32);
275       io.mapRequired("s16",      bt.s16);
276       io.mapRequired("s8",       bt.s8);
277       io.mapRequired("f",        bt.f);
278       io.mapRequired("d",        bt.d);
279       io.mapRequired("h8",       bt.h8);
280       io.mapRequired("h16",      bt.h16);
281       io.mapRequired("h32",      bt.h32);
282       io.mapRequired("h64",      bt.h64);
283     }
284   };
285 }
286 }
287 
288 
289 //
290 // Test the reading of all built-in scalar conversions
291 //
TEST(YAMLIO,TestReadBuiltInTypes)292 TEST(YAMLIO, TestReadBuiltInTypes) {
293   BuiltInTypes map;
294   Input yin("---\n"
295             "str:      hello there\n"
296             "stdstr:   hello where?\n"
297             "u64:      5000000000\n"
298             "u32:      4000000000\n"
299             "u16:      65000\n"
300             "u8:       255\n"
301             "b:        false\n"
302             "s64:      -5000000000\n"
303             "s32:      -2000000000\n"
304             "s16:      -32000\n"
305             "s8:       -127\n"
306             "f:        137.125\n"
307             "d:        -2.8625\n"
308             "h8:       0xFF\n"
309             "h16:      0x8765\n"
310             "h32:      0xFEDCBA98\n"
311             "h64:      0xFEDCBA9876543210\n"
312            "...\n");
313   yin >> map;
314 
315   EXPECT_FALSE(yin.error());
316   EXPECT_TRUE(map.str.equals("hello there"));
317   EXPECT_TRUE(map.stdstr == "hello where?");
318   EXPECT_EQ(map.u64, 5000000000ULL);
319   EXPECT_EQ(map.u32, 4000000000U);
320   EXPECT_EQ(map.u16, 65000);
321   EXPECT_EQ(map.u8,  255);
322   EXPECT_EQ(map.b,   false);
323   EXPECT_EQ(map.s64, -5000000000LL);
324   EXPECT_EQ(map.s32, -2000000000L);
325   EXPECT_EQ(map.s16, -32000);
326   EXPECT_EQ(map.s8,  -127);
327   EXPECT_EQ(map.f,   137.125);
328   EXPECT_EQ(map.d,   -2.8625);
329   EXPECT_EQ(map.h8,  Hex8(255));
330   EXPECT_EQ(map.h16, Hex16(0x8765));
331   EXPECT_EQ(map.h32, Hex32(0xFEDCBA98));
332   EXPECT_EQ(map.h64, Hex64(0xFEDCBA9876543210LL));
333 }
334 
335 
336 //
337 // Test writing then reading back all built-in scalar types
338 //
TEST(YAMLIO,TestReadWriteBuiltInTypes)339 TEST(YAMLIO, TestReadWriteBuiltInTypes) {
340   std::string intermediate;
341   {
342     BuiltInTypes map;
343     map.str = "one two";
344     map.stdstr = "three four";
345     map.u64 = 6000000000ULL;
346     map.u32 = 3000000000U;
347     map.u16 = 50000;
348     map.u8  = 254;
349     map.b   = true;
350     map.s64 = -6000000000LL;
351     map.s32 = -2000000000;
352     map.s16 = -32000;
353     map.s8  = -128;
354     map.f   = 3.25;
355     map.d   = -2.8625;
356     map.h8  = 254;
357     map.h16 = 50000;
358     map.h32 = 3000000000U;
359     map.h64 = 6000000000LL;
360 
361     llvm::raw_string_ostream ostr(intermediate);
362     Output yout(ostr);
363     yout << map;
364   }
365 
366   {
367     Input yin(intermediate);
368     BuiltInTypes map;
369     yin >> map;
370 
371     EXPECT_FALSE(yin.error());
372     EXPECT_TRUE(map.str.equals("one two"));
373     EXPECT_TRUE(map.stdstr == "three four");
374     EXPECT_EQ(map.u64,      6000000000ULL);
375     EXPECT_EQ(map.u32,      3000000000U);
376     EXPECT_EQ(map.u16,      50000);
377     EXPECT_EQ(map.u8,       254);
378     EXPECT_EQ(map.b,        true);
379     EXPECT_EQ(map.s64,      -6000000000LL);
380     EXPECT_EQ(map.s32,      -2000000000L);
381     EXPECT_EQ(map.s16,      -32000);
382     EXPECT_EQ(map.s8,       -128);
383     EXPECT_EQ(map.f,        3.25);
384     EXPECT_EQ(map.d,        -2.8625);
385     EXPECT_EQ(map.h8,       Hex8(254));
386     EXPECT_EQ(map.h16,      Hex16(50000));
387     EXPECT_EQ(map.h32,      Hex32(3000000000U));
388     EXPECT_EQ(map.h64,      Hex64(6000000000LL));
389   }
390 }
391 
392 //===----------------------------------------------------------------------===//
393 //  Test endian-aware types
394 //===----------------------------------------------------------------------===//
395 
396 struct EndianTypes {
397   typedef llvm::support::detail::packed_endian_specific_integral<
398       float, llvm::support::little, llvm::support::unaligned>
399       ulittle_float;
400   typedef llvm::support::detail::packed_endian_specific_integral<
401       double, llvm::support::little, llvm::support::unaligned>
402       ulittle_double;
403 
404   llvm::support::ulittle64_t u64;
405   llvm::support::ulittle32_t u32;
406   llvm::support::ulittle16_t u16;
407   llvm::support::little64_t s64;
408   llvm::support::little32_t s32;
409   llvm::support::little16_t s16;
410   ulittle_float f;
411   ulittle_double d;
412 };
413 
414 namespace llvm {
415 namespace yaml {
416 template <> struct MappingTraits<EndianTypes> {
mappingllvm::yaml::MappingTraits417   static void mapping(IO &io, EndianTypes &et) {
418     io.mapRequired("u64", et.u64);
419     io.mapRequired("u32", et.u32);
420     io.mapRequired("u16", et.u16);
421     io.mapRequired("s64", et.s64);
422     io.mapRequired("s32", et.s32);
423     io.mapRequired("s16", et.s16);
424     io.mapRequired("f", et.f);
425     io.mapRequired("d", et.d);
426   }
427 };
428 }
429 }
430 
431 //
432 // Test the reading of all endian scalar conversions
433 //
TEST(YAMLIO,TestReadEndianTypes)434 TEST(YAMLIO, TestReadEndianTypes) {
435   EndianTypes map;
436   Input yin("---\n"
437             "u64:      5000000000\n"
438             "u32:      4000000000\n"
439             "u16:      65000\n"
440             "s64:      -5000000000\n"
441             "s32:      -2000000000\n"
442             "s16:      -32000\n"
443             "f:        3.25\n"
444             "d:        -2.8625\n"
445             "...\n");
446   yin >> map;
447 
448   EXPECT_FALSE(yin.error());
449   EXPECT_EQ(map.u64, 5000000000ULL);
450   EXPECT_EQ(map.u32, 4000000000U);
451   EXPECT_EQ(map.u16, 65000);
452   EXPECT_EQ(map.s64, -5000000000LL);
453   EXPECT_EQ(map.s32, -2000000000L);
454   EXPECT_EQ(map.s16, -32000);
455   EXPECT_EQ(map.f, 3.25f);
456   EXPECT_EQ(map.d, -2.8625);
457 }
458 
459 //
460 // Test writing then reading back all endian-aware scalar types
461 //
TEST(YAMLIO,TestReadWriteEndianTypes)462 TEST(YAMLIO, TestReadWriteEndianTypes) {
463   std::string intermediate;
464   {
465     EndianTypes map;
466     map.u64 = 6000000000ULL;
467     map.u32 = 3000000000U;
468     map.u16 = 50000;
469     map.s64 = -6000000000LL;
470     map.s32 = -2000000000;
471     map.s16 = -32000;
472     map.f = 3.25f;
473     map.d = -2.8625;
474 
475     llvm::raw_string_ostream ostr(intermediate);
476     Output yout(ostr);
477     yout << map;
478   }
479 
480   {
481     Input yin(intermediate);
482     EndianTypes map;
483     yin >> map;
484 
485     EXPECT_FALSE(yin.error());
486     EXPECT_EQ(map.u64, 6000000000ULL);
487     EXPECT_EQ(map.u32, 3000000000U);
488     EXPECT_EQ(map.u16, 50000);
489     EXPECT_EQ(map.s64, -6000000000LL);
490     EXPECT_EQ(map.s32, -2000000000L);
491     EXPECT_EQ(map.s16, -32000);
492     EXPECT_EQ(map.f, 3.25f);
493     EXPECT_EQ(map.d, -2.8625);
494   }
495 }
496 
497 struct StringTypes {
498   llvm::StringRef str1;
499   llvm::StringRef str2;
500   llvm::StringRef str3;
501   llvm::StringRef str4;
502   llvm::StringRef str5;
503   llvm::StringRef str6;
504   llvm::StringRef str7;
505   llvm::StringRef str8;
506   llvm::StringRef str9;
507   llvm::StringRef str10;
508   llvm::StringRef str11;
509   std::string stdstr1;
510   std::string stdstr2;
511   std::string stdstr3;
512   std::string stdstr4;
513   std::string stdstr5;
514   std::string stdstr6;
515   std::string stdstr7;
516   std::string stdstr8;
517   std::string stdstr9;
518   std::string stdstr10;
519   std::string stdstr11;
520 };
521 
522 namespace llvm {
523 namespace yaml {
524   template <>
525   struct MappingTraits<StringTypes> {
mappingllvm::yaml::MappingTraits526     static void mapping(IO &io, StringTypes& st) {
527       io.mapRequired("str1",      st.str1);
528       io.mapRequired("str2",      st.str2);
529       io.mapRequired("str3",      st.str3);
530       io.mapRequired("str4",      st.str4);
531       io.mapRequired("str5",      st.str5);
532       io.mapRequired("str6",      st.str6);
533       io.mapRequired("str7",      st.str7);
534       io.mapRequired("str8",      st.str8);
535       io.mapRequired("str9",      st.str9);
536       io.mapRequired("str10",     st.str10);
537       io.mapRequired("str11",     st.str11);
538       io.mapRequired("stdstr1",   st.stdstr1);
539       io.mapRequired("stdstr2",   st.stdstr2);
540       io.mapRequired("stdstr3",   st.stdstr3);
541       io.mapRequired("stdstr4",   st.stdstr4);
542       io.mapRequired("stdstr5",   st.stdstr5);
543       io.mapRequired("stdstr6",   st.stdstr6);
544       io.mapRequired("stdstr7",   st.stdstr7);
545       io.mapRequired("stdstr8",   st.stdstr8);
546       io.mapRequired("stdstr9",   st.stdstr9);
547       io.mapRequired("stdstr10",  st.stdstr10);
548       io.mapRequired("stdstr11",  st.stdstr11);
549     }
550   };
551 }
552 }
553 
TEST(YAMLIO,TestReadWriteStringTypes)554 TEST(YAMLIO, TestReadWriteStringTypes) {
555   std::string intermediate;
556   {
557     StringTypes map;
558     map.str1 = "'aaa";
559     map.str2 = "\"bbb";
560     map.str3 = "`ccc";
561     map.str4 = "@ddd";
562     map.str5 = "";
563     map.str6 = "0000000004000000";
564     map.str7 = "true";
565     map.str8 = "FALSE";
566     map.str9 = "~";
567     map.str10 = "0.2e20";
568     map.str11 = "0x30";
569     map.stdstr1 = "'eee";
570     map.stdstr2 = "\"fff";
571     map.stdstr3 = "`ggg";
572     map.stdstr4 = "@hhh";
573     map.stdstr5 = "";
574     map.stdstr6 = "0000000004000000";
575     map.stdstr7 = "true";
576     map.stdstr8 = "FALSE";
577     map.stdstr9 = "~";
578     map.stdstr10 = "0.2e20";
579     map.stdstr11 = "0x30";
580 
581     llvm::raw_string_ostream ostr(intermediate);
582     Output yout(ostr);
583     yout << map;
584   }
585 
586   llvm::StringRef flowOut(intermediate);
587   EXPECT_NE(llvm::StringRef::npos, flowOut.find("'''aaa"));
588   EXPECT_NE(llvm::StringRef::npos, flowOut.find("'\"bbb'"));
589   EXPECT_NE(llvm::StringRef::npos, flowOut.find("'`ccc'"));
590   EXPECT_NE(llvm::StringRef::npos, flowOut.find("'@ddd'"));
591   EXPECT_NE(llvm::StringRef::npos, flowOut.find("''\n"));
592   EXPECT_NE(llvm::StringRef::npos, flowOut.find("'0000000004000000'\n"));
593   EXPECT_NE(llvm::StringRef::npos, flowOut.find("'true'\n"));
594   EXPECT_NE(llvm::StringRef::npos, flowOut.find("'FALSE'\n"));
595   EXPECT_NE(llvm::StringRef::npos, flowOut.find("'~'\n"));
596   EXPECT_NE(llvm::StringRef::npos, flowOut.find("'0.2e20'\n"));
597   EXPECT_NE(llvm::StringRef::npos, flowOut.find("'0x30'\n"));
598   EXPECT_NE(std::string::npos, flowOut.find("'''eee"));
599   EXPECT_NE(std::string::npos, flowOut.find("'\"fff'"));
600   EXPECT_NE(std::string::npos, flowOut.find("'`ggg'"));
601   EXPECT_NE(std::string::npos, flowOut.find("'@hhh'"));
602   EXPECT_NE(std::string::npos, flowOut.find("''\n"));
603   EXPECT_NE(std::string::npos, flowOut.find("'0000000004000000'\n"));
604 
605   {
606     Input yin(intermediate);
607     StringTypes map;
608     yin >> map;
609 
610     EXPECT_FALSE(yin.error());
611     EXPECT_TRUE(map.str1.equals("'aaa"));
612     EXPECT_TRUE(map.str2.equals("\"bbb"));
613     EXPECT_TRUE(map.str3.equals("`ccc"));
614     EXPECT_TRUE(map.str4.equals("@ddd"));
615     EXPECT_TRUE(map.str5.equals(""));
616     EXPECT_TRUE(map.str6.equals("0000000004000000"));
617     EXPECT_TRUE(map.stdstr1 == "'eee");
618     EXPECT_TRUE(map.stdstr2 == "\"fff");
619     EXPECT_TRUE(map.stdstr3 == "`ggg");
620     EXPECT_TRUE(map.stdstr4 == "@hhh");
621     EXPECT_TRUE(map.stdstr5 == "");
622     EXPECT_TRUE(map.stdstr6 == "0000000004000000");
623   }
624 }
625 
626 //===----------------------------------------------------------------------===//
627 //  Test ScalarEnumerationTraits
628 //===----------------------------------------------------------------------===//
629 
630 enum Colors {
631     cRed,
632     cBlue,
633     cGreen,
634     cYellow
635 };
636 
637 struct ColorMap {
638   Colors      c1;
639   Colors      c2;
640   Colors      c3;
641   Colors      c4;
642   Colors      c5;
643   Colors      c6;
644 };
645 
646 namespace llvm {
647 namespace yaml {
648   template <>
649   struct ScalarEnumerationTraits<Colors> {
enumerationllvm::yaml::ScalarEnumerationTraits650     static void enumeration(IO &io, Colors &value) {
651       io.enumCase(value, "red",   cRed);
652       io.enumCase(value, "blue",  cBlue);
653       io.enumCase(value, "green", cGreen);
654       io.enumCase(value, "yellow",cYellow);
655     }
656   };
657   template <>
658   struct MappingTraits<ColorMap> {
mappingllvm::yaml::MappingTraits659     static void mapping(IO &io, ColorMap& c) {
660       io.mapRequired("c1", c.c1);
661       io.mapRequired("c2", c.c2);
662       io.mapRequired("c3", c.c3);
663       io.mapOptional("c4", c.c4, cBlue);   // supplies default
664       io.mapOptional("c5", c.c5, cYellow); // supplies default
665       io.mapOptional("c6", c.c6, cRed);    // supplies default
666     }
667   };
668 }
669 }
670 
671 
672 //
673 // Test reading enumerated scalars
674 //
TEST(YAMLIO,TestEnumRead)675 TEST(YAMLIO, TestEnumRead) {
676   ColorMap map;
677   Input yin("---\n"
678             "c1:  blue\n"
679             "c2:  red\n"
680             "c3:  green\n"
681             "c5:  yellow\n"
682             "...\n");
683   yin >> map;
684 
685   EXPECT_FALSE(yin.error());
686   EXPECT_EQ(cBlue,  map.c1);
687   EXPECT_EQ(cRed,   map.c2);
688   EXPECT_EQ(cGreen, map.c3);
689   EXPECT_EQ(cBlue,  map.c4);  // tests default
690   EXPECT_EQ(cYellow,map.c5);  // tests overridden
691   EXPECT_EQ(cRed,   map.c6);  // tests default
692 }
693 
694 
695 
696 //===----------------------------------------------------------------------===//
697 //  Test ScalarBitSetTraits
698 //===----------------------------------------------------------------------===//
699 
700 enum MyFlags {
701   flagNone    = 0,
702   flagBig     = 1 << 0,
703   flagFlat    = 1 << 1,
704   flagRound   = 1 << 2,
705   flagPointy  = 1 << 3
706 };
operator |(MyFlags a,MyFlags b)707 inline MyFlags operator|(MyFlags a, MyFlags b) {
708   return static_cast<MyFlags>(
709                       static_cast<uint32_t>(a) | static_cast<uint32_t>(b));
710 }
711 
712 struct FlagsMap {
713   MyFlags     f1;
714   MyFlags     f2;
715   MyFlags     f3;
716   MyFlags     f4;
717 };
718 
719 
720 namespace llvm {
721 namespace yaml {
722   template <>
723   struct ScalarBitSetTraits<MyFlags> {
bitsetllvm::yaml::ScalarBitSetTraits724     static void bitset(IO &io, MyFlags &value) {
725       io.bitSetCase(value, "big",   flagBig);
726       io.bitSetCase(value, "flat",  flagFlat);
727       io.bitSetCase(value, "round", flagRound);
728       io.bitSetCase(value, "pointy",flagPointy);
729     }
730   };
731   template <>
732   struct MappingTraits<FlagsMap> {
mappingllvm::yaml::MappingTraits733     static void mapping(IO &io, FlagsMap& c) {
734       io.mapRequired("f1", c.f1);
735       io.mapRequired("f2", c.f2);
736       io.mapRequired("f3", c.f3);
737       io.mapOptional("f4", c.f4, MyFlags(flagRound));
738      }
739   };
740 }
741 }
742 
743 
744 //
745 // Test reading flow sequence representing bit-mask values
746 //
TEST(YAMLIO,TestFlagsRead)747 TEST(YAMLIO, TestFlagsRead) {
748   FlagsMap map;
749   Input yin("---\n"
750             "f1:  [ big ]\n"
751             "f2:  [ round, flat ]\n"
752             "f3:  []\n"
753             "...\n");
754   yin >> map;
755 
756   EXPECT_FALSE(yin.error());
757   EXPECT_EQ(flagBig,              map.f1);
758   EXPECT_EQ(flagRound|flagFlat,   map.f2);
759   EXPECT_EQ(flagNone,             map.f3);  // check empty set
760   EXPECT_EQ(flagRound,            map.f4);  // check optional key
761 }
762 
763 
764 //
765 // Test writing then reading back bit-mask values
766 //
TEST(YAMLIO,TestReadWriteFlags)767 TEST(YAMLIO, TestReadWriteFlags) {
768   std::string intermediate;
769   {
770     FlagsMap map;
771     map.f1 = flagBig;
772     map.f2 = flagRound | flagFlat;
773     map.f3 = flagNone;
774     map.f4 = flagNone;
775 
776     llvm::raw_string_ostream ostr(intermediate);
777     Output yout(ostr);
778     yout << map;
779   }
780 
781   {
782     Input yin(intermediate);
783     FlagsMap map2;
784     yin >> map2;
785 
786     EXPECT_FALSE(yin.error());
787     EXPECT_EQ(flagBig,              map2.f1);
788     EXPECT_EQ(flagRound|flagFlat,   map2.f2);
789     EXPECT_EQ(flagNone,             map2.f3);
790     //EXPECT_EQ(flagRound,            map2.f4);  // check optional key
791   }
792 }
793 
794 
795 
796 //===----------------------------------------------------------------------===//
797 //  Test ScalarTraits
798 //===----------------------------------------------------------------------===//
799 
800 struct MyCustomType {
801   int length;
802   int width;
803 };
804 
805 struct MyCustomTypeMap {
806   MyCustomType     f1;
807   MyCustomType     f2;
808   int              f3;
809 };
810 
811 
812 namespace llvm {
813 namespace yaml {
814   template <>
815   struct MappingTraits<MyCustomTypeMap> {
mappingllvm::yaml::MappingTraits816     static void mapping(IO &io, MyCustomTypeMap& s) {
817       io.mapRequired("f1", s.f1);
818       io.mapRequired("f2", s.f2);
819       io.mapRequired("f3", s.f3);
820      }
821   };
822   // MyCustomType is formatted as a yaml scalar.  A value of
823   // {length=3, width=4} would be represented in yaml as "3 by 4".
824   template<>
825   struct ScalarTraits<MyCustomType> {
outputllvm::yaml::ScalarTraits826     static void output(const MyCustomType &value, void* ctxt, llvm::raw_ostream &out) {
827       out << llvm::format("%d by %d", value.length, value.width);
828     }
inputllvm::yaml::ScalarTraits829     static StringRef input(StringRef scalar, void* ctxt, MyCustomType &value) {
830       size_t byStart = scalar.find("by");
831       if ( byStart != StringRef::npos ) {
832         StringRef lenStr = scalar.slice(0, byStart);
833         lenStr = lenStr.rtrim();
834         if ( lenStr.getAsInteger(0, value.length) ) {
835           return "malformed length";
836         }
837         StringRef widthStr = scalar.drop_front(byStart+2);
838         widthStr = widthStr.ltrim();
839         if ( widthStr.getAsInteger(0, value.width) ) {
840           return "malformed width";
841         }
842         return StringRef();
843       }
844       else {
845           return "malformed by";
846       }
847     }
mustQuotellvm::yaml::ScalarTraits848     static bool mustQuote(StringRef) { return true; }
849   };
850 }
851 }
852 
853 
854 //
855 // Test writing then reading back custom values
856 //
TEST(YAMLIO,TestReadWriteMyCustomType)857 TEST(YAMLIO, TestReadWriteMyCustomType) {
858   std::string intermediate;
859   {
860     MyCustomTypeMap map;
861     map.f1.length = 1;
862     map.f1.width  = 4;
863     map.f2.length = 100;
864     map.f2.width  = 400;
865     map.f3 = 10;
866 
867     llvm::raw_string_ostream ostr(intermediate);
868     Output yout(ostr);
869     yout << map;
870   }
871 
872   {
873     Input yin(intermediate);
874     MyCustomTypeMap map2;
875     yin >> map2;
876 
877     EXPECT_FALSE(yin.error());
878     EXPECT_EQ(1,      map2.f1.length);
879     EXPECT_EQ(4,      map2.f1.width);
880     EXPECT_EQ(100,    map2.f2.length);
881     EXPECT_EQ(400,    map2.f2.width);
882     EXPECT_EQ(10,     map2.f3);
883   }
884 }
885 
886 
887 //===----------------------------------------------------------------------===//
888 //  Test BlockScalarTraits
889 //===----------------------------------------------------------------------===//
890 
891 struct MultilineStringType {
892   std::string str;
893 };
894 
895 struct MultilineStringTypeMap {
896   MultilineStringType name;
897   MultilineStringType description;
898   MultilineStringType ingredients;
899   MultilineStringType recipes;
900   MultilineStringType warningLabels;
901   MultilineStringType documentation;
902   int price;
903 };
904 
905 namespace llvm {
906 namespace yaml {
907   template <>
908   struct MappingTraits<MultilineStringTypeMap> {
mappingllvm::yaml::MappingTraits909     static void mapping(IO &io, MultilineStringTypeMap& s) {
910       io.mapRequired("name", s.name);
911       io.mapRequired("description", s.description);
912       io.mapRequired("ingredients", s.ingredients);
913       io.mapRequired("recipes", s.recipes);
914       io.mapRequired("warningLabels", s.warningLabels);
915       io.mapRequired("documentation", s.documentation);
916       io.mapRequired("price", s.price);
917      }
918   };
919 
920   // MultilineStringType is formatted as a yaml block literal scalar. A value of
921   // "Hello\nWorld" would be represented in yaml as
922   //  |
923   //    Hello
924   //    World
925   template <>
926   struct BlockScalarTraits<MultilineStringType> {
outputllvm::yaml::BlockScalarTraits927     static void output(const MultilineStringType &value, void *ctxt,
928                        llvm::raw_ostream &out) {
929       out << value.str;
930     }
inputllvm::yaml::BlockScalarTraits931     static StringRef input(StringRef scalar, void *ctxt,
932                            MultilineStringType &value) {
933       value.str = scalar.str();
934       return StringRef();
935     }
936   };
937 }
938 }
939 
940 LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(MultilineStringType)
941 
942 //
943 // Test writing then reading back custom values
944 //
TEST(YAMLIO,TestReadWriteMultilineStringType)945 TEST(YAMLIO, TestReadWriteMultilineStringType) {
946   std::string intermediate;
947   {
948     MultilineStringTypeMap map;
949     map.name.str = "An Item";
950     map.description.str = "Hello\nWorld";
951     map.ingredients.str = "SubItem 1\nSub Item 2\n\nSub Item 3\n";
952     map.recipes.str = "\n\nTest 1\n\n\n";
953     map.warningLabels.str = "";
954     map.documentation.str = "\n\n";
955     map.price = 350;
956 
957     llvm::raw_string_ostream ostr(intermediate);
958     Output yout(ostr);
959     yout << map;
960   }
961   {
962     Input yin(intermediate);
963     MultilineStringTypeMap map2;
964     yin >> map2;
965 
966     EXPECT_FALSE(yin.error());
967     EXPECT_EQ(map2.name.str, "An Item\n");
968     EXPECT_EQ(map2.description.str, "Hello\nWorld\n");
969     EXPECT_EQ(map2.ingredients.str, "SubItem 1\nSub Item 2\n\nSub Item 3\n");
970     EXPECT_EQ(map2.recipes.str, "\n\nTest 1\n");
971     EXPECT_TRUE(map2.warningLabels.str.empty());
972     EXPECT_TRUE(map2.documentation.str.empty());
973     EXPECT_EQ(map2.price, 350);
974   }
975 }
976 
977 //
978 // Test writing then reading back custom values
979 //
TEST(YAMLIO,TestReadWriteBlockScalarDocuments)980 TEST(YAMLIO, TestReadWriteBlockScalarDocuments) {
981   std::string intermediate;
982   {
983     std::vector<MultilineStringType> documents;
984     MultilineStringType doc;
985     doc.str = "Hello\nWorld";
986     documents.push_back(doc);
987 
988     llvm::raw_string_ostream ostr(intermediate);
989     Output yout(ostr);
990     yout << documents;
991 
992     // Verify that the block scalar header was written out on the same line
993     // as the document marker.
994     EXPECT_NE(llvm::StringRef::npos, llvm::StringRef(ostr.str()).find("--- |"));
995   }
996   {
997     Input yin(intermediate);
998     std::vector<MultilineStringType> documents2;
999     yin >> documents2;
1000 
1001     EXPECT_FALSE(yin.error());
1002     EXPECT_EQ(documents2.size(), size_t(1));
1003     EXPECT_EQ(documents2[0].str, "Hello\nWorld\n");
1004   }
1005 }
1006 
TEST(YAMLIO,TestReadWriteBlockScalarValue)1007 TEST(YAMLIO, TestReadWriteBlockScalarValue) {
1008   std::string intermediate;
1009   {
1010     MultilineStringType doc;
1011     doc.str = "Just a block\nscalar doc";
1012 
1013     llvm::raw_string_ostream ostr(intermediate);
1014     Output yout(ostr);
1015     yout << doc;
1016   }
1017   {
1018     Input yin(intermediate);
1019     MultilineStringType doc;
1020     yin >> doc;
1021 
1022     EXPECT_FALSE(yin.error());
1023     EXPECT_EQ(doc.str, "Just a block\nscalar doc\n");
1024   }
1025 }
1026 
1027 //===----------------------------------------------------------------------===//
1028 //  Test flow sequences
1029 //===----------------------------------------------------------------------===//
1030 
1031 LLVM_YAML_STRONG_TYPEDEF(int, MyNumber)
1032 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(MyNumber)
1033 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::StringRef)
1034 
1035 namespace llvm {
1036 namespace yaml {
1037   template<>
1038   struct ScalarTraits<MyNumber> {
outputllvm::yaml::ScalarTraits1039     static void output(const MyNumber &value, void *, llvm::raw_ostream &out) {
1040       out << value;
1041     }
1042 
inputllvm::yaml::ScalarTraits1043     static StringRef input(StringRef scalar, void *, MyNumber &value) {
1044       long long n;
1045       if ( getAsSignedInteger(scalar, 0, n) )
1046         return "invalid number";
1047       value = n;
1048       return StringRef();
1049     }
1050 
mustQuotellvm::yaml::ScalarTraits1051     static bool mustQuote(StringRef) { return false; }
1052   };
1053 }
1054 }
1055 
1056 struct NameAndNumbers {
1057   llvm::StringRef               name;
1058   std::vector<llvm::StringRef>  strings;
1059   std::vector<MyNumber>         single;
1060   std::vector<MyNumber>         numbers;
1061 };
1062 
1063 namespace llvm {
1064 namespace yaml {
1065   template <>
1066   struct MappingTraits<NameAndNumbers> {
mappingllvm::yaml::MappingTraits1067     static void mapping(IO &io, NameAndNumbers& nn) {
1068       io.mapRequired("name",     nn.name);
1069       io.mapRequired("strings",  nn.strings);
1070       io.mapRequired("single",   nn.single);
1071       io.mapRequired("numbers",  nn.numbers);
1072     }
1073   };
1074 }
1075 }
1076 
1077 typedef std::vector<MyNumber> MyNumberFlowSequence;
1078 
1079 LLVM_YAML_IS_SEQUENCE_VECTOR(MyNumberFlowSequence)
1080 
1081 struct NameAndNumbersFlow {
1082   llvm::StringRef                    name;
1083   std::vector<MyNumberFlowSequence>  sequenceOfNumbers;
1084 };
1085 
1086 namespace llvm {
1087 namespace yaml {
1088   template <>
1089   struct MappingTraits<NameAndNumbersFlow> {
mappingllvm::yaml::MappingTraits1090     static void mapping(IO &io, NameAndNumbersFlow& nn) {
1091       io.mapRequired("name",     nn.name);
1092       io.mapRequired("sequenceOfNumbers",  nn.sequenceOfNumbers);
1093     }
1094   };
1095 }
1096 }
1097 
1098 //
1099 // Test writing then reading back custom values
1100 //
TEST(YAMLIO,TestReadWriteMyFlowSequence)1101 TEST(YAMLIO, TestReadWriteMyFlowSequence) {
1102   std::string intermediate;
1103   {
1104     NameAndNumbers map;
1105     map.name  = "hello";
1106     map.strings.push_back(llvm::StringRef("one"));
1107     map.strings.push_back(llvm::StringRef("two"));
1108     map.single.push_back(1);
1109     map.numbers.push_back(10);
1110     map.numbers.push_back(-30);
1111     map.numbers.push_back(1024);
1112 
1113     llvm::raw_string_ostream ostr(intermediate);
1114     Output yout(ostr);
1115     yout << map;
1116 
1117     // Verify sequences were written in flow style
1118     ostr.flush();
1119     llvm::StringRef flowOut(intermediate);
1120     EXPECT_NE(llvm::StringRef::npos, flowOut.find("one, two"));
1121     EXPECT_NE(llvm::StringRef::npos, flowOut.find("10, -30, 1024"));
1122   }
1123 
1124   {
1125     Input yin(intermediate);
1126     NameAndNumbers map2;
1127     yin >> map2;
1128 
1129     EXPECT_FALSE(yin.error());
1130     EXPECT_TRUE(map2.name.equals("hello"));
1131     EXPECT_EQ(map2.strings.size(), 2UL);
1132     EXPECT_TRUE(map2.strings[0].equals("one"));
1133     EXPECT_TRUE(map2.strings[1].equals("two"));
1134     EXPECT_EQ(map2.single.size(), 1UL);
1135     EXPECT_EQ(1,       map2.single[0]);
1136     EXPECT_EQ(map2.numbers.size(), 3UL);
1137     EXPECT_EQ(10,      map2.numbers[0]);
1138     EXPECT_EQ(-30,     map2.numbers[1]);
1139     EXPECT_EQ(1024,    map2.numbers[2]);
1140   }
1141 }
1142 
1143 
1144 //
1145 // Test writing then reading back a sequence of flow sequences.
1146 //
TEST(YAMLIO,TestReadWriteSequenceOfMyFlowSequence)1147 TEST(YAMLIO, TestReadWriteSequenceOfMyFlowSequence) {
1148   std::string intermediate;
1149   {
1150     NameAndNumbersFlow map;
1151     map.name  = "hello";
1152     MyNumberFlowSequence single = { 0 };
1153     MyNumberFlowSequence numbers = { 12, 1, -512 };
1154     map.sequenceOfNumbers.push_back(single);
1155     map.sequenceOfNumbers.push_back(numbers);
1156     map.sequenceOfNumbers.push_back(MyNumberFlowSequence());
1157 
1158     llvm::raw_string_ostream ostr(intermediate);
1159     Output yout(ostr);
1160     yout << map;
1161 
1162     // Verify sequences were written in flow style
1163     // and that the parent sequence used '-'.
1164     ostr.flush();
1165     llvm::StringRef flowOut(intermediate);
1166     EXPECT_NE(llvm::StringRef::npos, flowOut.find("- [ 0 ]"));
1167     EXPECT_NE(llvm::StringRef::npos, flowOut.find("- [ 12, 1, -512 ]"));
1168     EXPECT_NE(llvm::StringRef::npos, flowOut.find("- [  ]"));
1169   }
1170 
1171   {
1172     Input yin(intermediate);
1173     NameAndNumbersFlow map2;
1174     yin >> map2;
1175 
1176     EXPECT_FALSE(yin.error());
1177     EXPECT_TRUE(map2.name.equals("hello"));
1178     EXPECT_EQ(map2.sequenceOfNumbers.size(), 3UL);
1179     EXPECT_EQ(map2.sequenceOfNumbers[0].size(), 1UL);
1180     EXPECT_EQ(0,    map2.sequenceOfNumbers[0][0]);
1181     EXPECT_EQ(map2.sequenceOfNumbers[1].size(), 3UL);
1182     EXPECT_EQ(12,   map2.sequenceOfNumbers[1][0]);
1183     EXPECT_EQ(1,    map2.sequenceOfNumbers[1][1]);
1184     EXPECT_EQ(-512, map2.sequenceOfNumbers[1][2]);
1185     EXPECT_TRUE(map2.sequenceOfNumbers[2].empty());
1186   }
1187 }
1188 
1189 //===----------------------------------------------------------------------===//
1190 //  Test normalizing/denormalizing
1191 //===----------------------------------------------------------------------===//
1192 
1193 LLVM_YAML_STRONG_TYPEDEF(uint32_t, TotalSeconds)
1194 
1195 typedef std::vector<TotalSeconds> SecondsSequence;
1196 
1197 LLVM_YAML_IS_SEQUENCE_VECTOR(TotalSeconds)
1198 
1199 
1200 namespace llvm {
1201 namespace yaml {
1202   template <>
1203   struct MappingTraits<TotalSeconds> {
1204 
1205     class NormalizedSeconds {
1206     public:
NormalizedSeconds(IO & io)1207       NormalizedSeconds(IO &io)
1208         : hours(0), minutes(0), seconds(0) {
1209       }
NormalizedSeconds(IO &,TotalSeconds & secs)1210       NormalizedSeconds(IO &, TotalSeconds &secs)
1211         : hours(secs/3600),
1212           minutes((secs - (hours*3600))/60),
1213           seconds(secs % 60) {
1214       }
denormalize(IO &)1215       TotalSeconds denormalize(IO &) {
1216         return TotalSeconds(hours*3600 + minutes*60 + seconds);
1217       }
1218 
1219       uint32_t     hours;
1220       uint8_t      minutes;
1221       uint8_t      seconds;
1222     };
1223 
mappingllvm::yaml::MappingTraits1224     static void mapping(IO &io, TotalSeconds &secs) {
1225       MappingNormalization<NormalizedSeconds, TotalSeconds> keys(io, secs);
1226 
1227       io.mapOptional("hours",    keys->hours,    (uint32_t)0);
1228       io.mapOptional("minutes",  keys->minutes,  (uint8_t)0);
1229       io.mapRequired("seconds",  keys->seconds);
1230     }
1231   };
1232 }
1233 }
1234 
1235 
1236 //
1237 // Test the reading of a yaml sequence of mappings
1238 //
TEST(YAMLIO,TestReadMySecondsSequence)1239 TEST(YAMLIO, TestReadMySecondsSequence) {
1240   SecondsSequence seq;
1241   Input yin("---\n - hours:  1\n   seconds:  5\n - seconds:  59\n...\n");
1242   yin >> seq;
1243 
1244   EXPECT_FALSE(yin.error());
1245   EXPECT_EQ(seq.size(), 2UL);
1246   EXPECT_EQ(seq[0], 3605U);
1247   EXPECT_EQ(seq[1], 59U);
1248 }
1249 
1250 
1251 //
1252 // Test writing then reading back custom values
1253 //
TEST(YAMLIO,TestReadWriteMySecondsSequence)1254 TEST(YAMLIO, TestReadWriteMySecondsSequence) {
1255   std::string intermediate;
1256   {
1257     SecondsSequence seq;
1258     seq.push_back(4000);
1259     seq.push_back(500);
1260     seq.push_back(59);
1261 
1262     llvm::raw_string_ostream ostr(intermediate);
1263     Output yout(ostr);
1264     yout << seq;
1265   }
1266   {
1267     Input yin(intermediate);
1268     SecondsSequence seq2;
1269     yin >> seq2;
1270 
1271     EXPECT_FALSE(yin.error());
1272     EXPECT_EQ(seq2.size(), 3UL);
1273     EXPECT_EQ(seq2[0], 4000U);
1274     EXPECT_EQ(seq2[1], 500U);
1275     EXPECT_EQ(seq2[2], 59U);
1276   }
1277 }
1278 
1279 
1280 //===----------------------------------------------------------------------===//
1281 //  Test dynamic typing
1282 //===----------------------------------------------------------------------===//
1283 
1284 enum AFlags {
1285     a1,
1286     a2,
1287     a3
1288 };
1289 
1290 enum BFlags {
1291     b1,
1292     b2,
1293     b3
1294 };
1295 
1296 enum Kind {
1297     kindA,
1298     kindB
1299 };
1300 
1301 struct KindAndFlags {
KindAndFlagsKindAndFlags1302   KindAndFlags() : kind(kindA), flags(0) { }
KindAndFlagsKindAndFlags1303   KindAndFlags(Kind k, uint32_t f) : kind(k), flags(f) { }
1304   Kind        kind;
1305   uint32_t    flags;
1306 };
1307 
1308 typedef std::vector<KindAndFlags> KindAndFlagsSequence;
1309 
1310 LLVM_YAML_IS_SEQUENCE_VECTOR(KindAndFlags)
1311 
1312 namespace llvm {
1313 namespace yaml {
1314   template <>
1315   struct ScalarEnumerationTraits<AFlags> {
enumerationllvm::yaml::ScalarEnumerationTraits1316     static void enumeration(IO &io, AFlags &value) {
1317       io.enumCase(value, "a1",  a1);
1318       io.enumCase(value, "a2",  a2);
1319       io.enumCase(value, "a3",  a3);
1320     }
1321   };
1322   template <>
1323   struct ScalarEnumerationTraits<BFlags> {
enumerationllvm::yaml::ScalarEnumerationTraits1324     static void enumeration(IO &io, BFlags &value) {
1325       io.enumCase(value, "b1",  b1);
1326       io.enumCase(value, "b2",  b2);
1327       io.enumCase(value, "b3",  b3);
1328     }
1329   };
1330   template <>
1331   struct ScalarEnumerationTraits<Kind> {
enumerationllvm::yaml::ScalarEnumerationTraits1332     static void enumeration(IO &io, Kind &value) {
1333       io.enumCase(value, "A",  kindA);
1334       io.enumCase(value, "B",  kindB);
1335     }
1336   };
1337   template <>
1338   struct MappingTraits<KindAndFlags> {
mappingllvm::yaml::MappingTraits1339     static void mapping(IO &io, KindAndFlags& kf) {
1340       io.mapRequired("kind",  kf.kind);
1341       // Type of "flags" field varies depending on "kind" field.
1342       // Use memcpy here to avoid breaking strict aliasing rules.
1343       if (kf.kind == kindA) {
1344         AFlags aflags = static_cast<AFlags>(kf.flags);
1345         io.mapRequired("flags", aflags);
1346         kf.flags = aflags;
1347       } else {
1348         BFlags bflags = static_cast<BFlags>(kf.flags);
1349         io.mapRequired("flags", bflags);
1350         kf.flags = bflags;
1351       }
1352     }
1353   };
1354 }
1355 }
1356 
1357 
1358 //
1359 // Test the reading of a yaml sequence dynamic types
1360 //
TEST(YAMLIO,TestReadKindAndFlagsSequence)1361 TEST(YAMLIO, TestReadKindAndFlagsSequence) {
1362   KindAndFlagsSequence seq;
1363   Input yin("---\n - kind:  A\n   flags:  a2\n - kind:  B\n   flags:  b1\n...\n");
1364   yin >> seq;
1365 
1366   EXPECT_FALSE(yin.error());
1367   EXPECT_EQ(seq.size(), 2UL);
1368   EXPECT_EQ(seq[0].kind,  kindA);
1369   EXPECT_EQ(seq[0].flags, (uint32_t)a2);
1370   EXPECT_EQ(seq[1].kind,  kindB);
1371   EXPECT_EQ(seq[1].flags, (uint32_t)b1);
1372 }
1373 
1374 //
1375 // Test writing then reading back dynamic types
1376 //
TEST(YAMLIO,TestReadWriteKindAndFlagsSequence)1377 TEST(YAMLIO, TestReadWriteKindAndFlagsSequence) {
1378   std::string intermediate;
1379   {
1380     KindAndFlagsSequence seq;
1381     seq.push_back(KindAndFlags(kindA,a1));
1382     seq.push_back(KindAndFlags(kindB,b1));
1383     seq.push_back(KindAndFlags(kindA,a2));
1384     seq.push_back(KindAndFlags(kindB,b2));
1385     seq.push_back(KindAndFlags(kindA,a3));
1386 
1387     llvm::raw_string_ostream ostr(intermediate);
1388     Output yout(ostr);
1389     yout << seq;
1390   }
1391   {
1392     Input yin(intermediate);
1393     KindAndFlagsSequence seq2;
1394     yin >> seq2;
1395 
1396     EXPECT_FALSE(yin.error());
1397     EXPECT_EQ(seq2.size(), 5UL);
1398     EXPECT_EQ(seq2[0].kind,  kindA);
1399     EXPECT_EQ(seq2[0].flags, (uint32_t)a1);
1400     EXPECT_EQ(seq2[1].kind,  kindB);
1401     EXPECT_EQ(seq2[1].flags, (uint32_t)b1);
1402     EXPECT_EQ(seq2[2].kind,  kindA);
1403     EXPECT_EQ(seq2[2].flags, (uint32_t)a2);
1404     EXPECT_EQ(seq2[3].kind,  kindB);
1405     EXPECT_EQ(seq2[3].flags, (uint32_t)b2);
1406     EXPECT_EQ(seq2[4].kind,  kindA);
1407     EXPECT_EQ(seq2[4].flags, (uint32_t)a3);
1408   }
1409 }
1410 
1411 
1412 //===----------------------------------------------------------------------===//
1413 //  Test document list
1414 //===----------------------------------------------------------------------===//
1415 
1416 struct FooBarMap {
1417   int foo;
1418   int bar;
1419 };
1420 typedef std::vector<FooBarMap> FooBarMapDocumentList;
1421 
1422 LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(FooBarMap)
1423 
1424 
1425 namespace llvm {
1426 namespace yaml {
1427   template <>
1428   struct MappingTraits<FooBarMap> {
mappingllvm::yaml::MappingTraits1429     static void mapping(IO &io, FooBarMap& fb) {
1430       io.mapRequired("foo",    fb.foo);
1431       io.mapRequired("bar",    fb.bar);
1432     }
1433   };
1434 }
1435 }
1436 
1437 
1438 //
1439 // Test the reading of a yaml mapping
1440 //
TEST(YAMLIO,TestDocRead)1441 TEST(YAMLIO, TestDocRead) {
1442   FooBarMap doc;
1443   Input yin("---\nfoo:  3\nbar:  5\n...\n");
1444   yin >> doc;
1445 
1446   EXPECT_FALSE(yin.error());
1447   EXPECT_EQ(doc.foo, 3);
1448   EXPECT_EQ(doc.bar,5);
1449 }
1450 
1451 
1452 
1453 //
1454 // Test writing then reading back a sequence of mappings
1455 //
TEST(YAMLIO,TestSequenceDocListWriteAndRead)1456 TEST(YAMLIO, TestSequenceDocListWriteAndRead) {
1457   std::string intermediate;
1458   {
1459     FooBarMap doc1;
1460     doc1.foo = 10;
1461     doc1.bar = -3;
1462     FooBarMap doc2;
1463     doc2.foo = 257;
1464     doc2.bar = 0;
1465     std::vector<FooBarMap> docList;
1466     docList.push_back(doc1);
1467     docList.push_back(doc2);
1468 
1469     llvm::raw_string_ostream ostr(intermediate);
1470     Output yout(ostr);
1471     yout << docList;
1472   }
1473 
1474 
1475   {
1476     Input yin(intermediate);
1477     std::vector<FooBarMap> docList2;
1478     yin >> docList2;
1479 
1480     EXPECT_FALSE(yin.error());
1481     EXPECT_EQ(docList2.size(), 2UL);
1482     FooBarMap& map1 = docList2[0];
1483     FooBarMap& map2 = docList2[1];
1484     EXPECT_EQ(map1.foo, 10);
1485     EXPECT_EQ(map1.bar, -3);
1486     EXPECT_EQ(map2.foo, 257);
1487     EXPECT_EQ(map2.bar, 0);
1488   }
1489 }
1490 
1491 //===----------------------------------------------------------------------===//
1492 //  Test document tags
1493 //===----------------------------------------------------------------------===//
1494 
1495 struct MyDouble {
MyDoubleMyDouble1496   MyDouble() : value(0.0) { }
MyDoubleMyDouble1497   MyDouble(double x) : value(x) { }
1498   double value;
1499 };
1500 
1501 LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(MyDouble)
1502 
1503 
1504 namespace llvm {
1505 namespace yaml {
1506   template <>
1507   struct MappingTraits<MyDouble> {
mappingllvm::yaml::MappingTraits1508     static void mapping(IO &io, MyDouble &d) {
1509       if (io.mapTag("!decimal", true)) {
1510         mappingDecimal(io, d);
1511       } else if (io.mapTag("!fraction")) {
1512         mappingFraction(io, d);
1513       }
1514     }
mappingDecimalllvm::yaml::MappingTraits1515     static void mappingDecimal(IO &io, MyDouble &d) {
1516       io.mapRequired("value", d.value);
1517     }
mappingFractionllvm::yaml::MappingTraits1518     static void mappingFraction(IO &io, MyDouble &d) {
1519         double num, denom;
1520         io.mapRequired("numerator",      num);
1521         io.mapRequired("denominator",    denom);
1522         // convert fraction to double
1523         d.value = num/denom;
1524     }
1525   };
1526  }
1527 }
1528 
1529 
1530 //
1531 // Test the reading of two different tagged yaml documents.
1532 //
TEST(YAMLIO,TestTaggedDocuments)1533 TEST(YAMLIO, TestTaggedDocuments) {
1534   std::vector<MyDouble> docList;
1535   Input yin("--- !decimal\nvalue:  3.0\n"
1536             "--- !fraction\nnumerator:  9.0\ndenominator:  2\n...\n");
1537   yin >> docList;
1538   EXPECT_FALSE(yin.error());
1539   EXPECT_EQ(docList.size(), 2UL);
1540   EXPECT_EQ(docList[0].value, 3.0);
1541   EXPECT_EQ(docList[1].value, 4.5);
1542 }
1543 
1544 
1545 
1546 //
1547 // Test writing then reading back tagged documents
1548 //
TEST(YAMLIO,TestTaggedDocumentsWriteAndRead)1549 TEST(YAMLIO, TestTaggedDocumentsWriteAndRead) {
1550   std::string intermediate;
1551   {
1552     MyDouble a(10.25);
1553     MyDouble b(-3.75);
1554     std::vector<MyDouble> docList;
1555     docList.push_back(a);
1556     docList.push_back(b);
1557 
1558     llvm::raw_string_ostream ostr(intermediate);
1559     Output yout(ostr);
1560     yout << docList;
1561   }
1562 
1563   {
1564     Input yin(intermediate);
1565     std::vector<MyDouble> docList2;
1566     yin >> docList2;
1567 
1568     EXPECT_FALSE(yin.error());
1569     EXPECT_EQ(docList2.size(), 2UL);
1570     EXPECT_EQ(docList2[0].value, 10.25);
1571     EXPECT_EQ(docList2[1].value, -3.75);
1572   }
1573 }
1574 
1575 
1576 //===----------------------------------------------------------------------===//
1577 //  Test mapping validation
1578 //===----------------------------------------------------------------------===//
1579 
1580 struct MyValidation {
1581   double value;
1582 };
1583 
1584 LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(MyValidation)
1585 
1586 namespace llvm {
1587 namespace yaml {
1588   template <>
1589   struct MappingTraits<MyValidation> {
mappingllvm::yaml::MappingTraits1590     static void mapping(IO &io, MyValidation &d) {
1591         io.mapRequired("value", d.value);
1592     }
validatellvm::yaml::MappingTraits1593     static StringRef validate(IO &io, MyValidation &d) {
1594         if (d.value < 0)
1595           return "negative value";
1596         return StringRef();
1597     }
1598   };
1599  }
1600 }
1601 
1602 
1603 //
1604 // Test that validate() is called and complains about the negative value.
1605 //
TEST(YAMLIO,TestValidatingInput)1606 TEST(YAMLIO, TestValidatingInput) {
1607   std::vector<MyValidation> docList;
1608   Input yin("--- \nvalue:  3.0\n"
1609             "--- \nvalue:  -1.0\n...\n",
1610             nullptr, suppressErrorMessages);
1611   yin >> docList;
1612   EXPECT_TRUE(!!yin.error());
1613 }
1614 
1615 //===----------------------------------------------------------------------===//
1616 //  Test flow mapping
1617 //===----------------------------------------------------------------------===//
1618 
1619 struct FlowFooBar {
1620   int foo;
1621   int bar;
1622 
FlowFooBarFlowFooBar1623   FlowFooBar() : foo(0), bar(0) {}
FlowFooBarFlowFooBar1624   FlowFooBar(int foo, int bar) : foo(foo), bar(bar) {}
1625 };
1626 
1627 typedef std::vector<FlowFooBar> FlowFooBarSequence;
1628 
1629 LLVM_YAML_IS_SEQUENCE_VECTOR(FlowFooBar)
1630 
1631 struct FlowFooBarDoc {
1632   FlowFooBar attribute;
1633   FlowFooBarSequence seq;
1634 };
1635 
1636 namespace llvm {
1637 namespace yaml {
1638   template <>
1639   struct MappingTraits<FlowFooBar> {
mappingllvm::yaml::MappingTraits1640     static void mapping(IO &io, FlowFooBar &fb) {
1641       io.mapRequired("foo", fb.foo);
1642       io.mapRequired("bar", fb.bar);
1643     }
1644 
1645     static const bool flow = true;
1646   };
1647 
1648   template <>
1649   struct MappingTraits<FlowFooBarDoc> {
mappingllvm::yaml::MappingTraits1650     static void mapping(IO &io, FlowFooBarDoc &fb) {
1651       io.mapRequired("attribute", fb.attribute);
1652       io.mapRequired("seq", fb.seq);
1653     }
1654   };
1655 }
1656 }
1657 
1658 //
1659 // Test writing then reading back custom mappings
1660 //
TEST(YAMLIO,TestReadWriteMyFlowMapping)1661 TEST(YAMLIO, TestReadWriteMyFlowMapping) {
1662   std::string intermediate;
1663   {
1664     FlowFooBarDoc doc;
1665     doc.attribute = FlowFooBar(42, 907);
1666     doc.seq.push_back(FlowFooBar(1, 2));
1667     doc.seq.push_back(FlowFooBar(0, 0));
1668     doc.seq.push_back(FlowFooBar(-1, 1024));
1669 
1670     llvm::raw_string_ostream ostr(intermediate);
1671     Output yout(ostr);
1672     yout << doc;
1673 
1674     // Verify that mappings were written in flow style
1675     ostr.flush();
1676     llvm::StringRef flowOut(intermediate);
1677     EXPECT_NE(llvm::StringRef::npos, flowOut.find("{ foo: 42, bar: 907 }"));
1678     EXPECT_NE(llvm::StringRef::npos, flowOut.find("- { foo: 1, bar: 2 }"));
1679     EXPECT_NE(llvm::StringRef::npos, flowOut.find("- { foo: 0, bar: 0 }"));
1680     EXPECT_NE(llvm::StringRef::npos, flowOut.find("- { foo: -1, bar: 1024 }"));
1681   }
1682 
1683   {
1684     Input yin(intermediate);
1685     FlowFooBarDoc doc2;
1686     yin >> doc2;
1687 
1688     EXPECT_FALSE(yin.error());
1689     EXPECT_EQ(doc2.attribute.foo, 42);
1690     EXPECT_EQ(doc2.attribute.bar, 907);
1691     EXPECT_EQ(doc2.seq.size(), 3UL);
1692     EXPECT_EQ(doc2.seq[0].foo, 1);
1693     EXPECT_EQ(doc2.seq[0].bar, 2);
1694     EXPECT_EQ(doc2.seq[1].foo, 0);
1695     EXPECT_EQ(doc2.seq[1].bar, 0);
1696     EXPECT_EQ(doc2.seq[2].foo, -1);
1697     EXPECT_EQ(doc2.seq[2].bar, 1024);
1698   }
1699 }
1700 
1701 //===----------------------------------------------------------------------===//
1702 //  Test error handling
1703 //===----------------------------------------------------------------------===//
1704 
1705 //
1706 // Test error handling of unknown enumerated scalar
1707 //
TEST(YAMLIO,TestColorsReadError)1708 TEST(YAMLIO, TestColorsReadError) {
1709   ColorMap map;
1710   Input yin("---\n"
1711             "c1:  blue\n"
1712             "c2:  purple\n"
1713             "c3:  green\n"
1714             "...\n",
1715             /*Ctxt=*/nullptr,
1716             suppressErrorMessages);
1717   yin >> map;
1718   EXPECT_TRUE(!!yin.error());
1719 }
1720 
1721 
1722 //
1723 // Test error handling of flow sequence with unknown value
1724 //
TEST(YAMLIO,TestFlagsReadError)1725 TEST(YAMLIO, TestFlagsReadError) {
1726   FlagsMap map;
1727   Input yin("---\n"
1728             "f1:  [ big ]\n"
1729             "f2:  [ round, hollow ]\n"
1730             "f3:  []\n"
1731             "...\n",
1732             /*Ctxt=*/nullptr,
1733             suppressErrorMessages);
1734   yin >> map;
1735 
1736   EXPECT_TRUE(!!yin.error());
1737 }
1738 
1739 
1740 //
1741 // Test error handling reading built-in uint8_t type
1742 //
1743 LLVM_YAML_IS_SEQUENCE_VECTOR(uint8_t)
TEST(YAMLIO,TestReadBuiltInTypesUint8Error)1744 TEST(YAMLIO, TestReadBuiltInTypesUint8Error) {
1745   std::vector<uint8_t> seq;
1746   Input yin("---\n"
1747             "- 255\n"
1748             "- 0\n"
1749             "- 257\n"
1750             "...\n",
1751             /*Ctxt=*/nullptr,
1752             suppressErrorMessages);
1753   yin >> seq;
1754 
1755   EXPECT_TRUE(!!yin.error());
1756 }
1757 
1758 
1759 //
1760 // Test error handling reading built-in uint16_t type
1761 //
1762 LLVM_YAML_IS_SEQUENCE_VECTOR(uint16_t)
TEST(YAMLIO,TestReadBuiltInTypesUint16Error)1763 TEST(YAMLIO, TestReadBuiltInTypesUint16Error) {
1764   std::vector<uint16_t> seq;
1765   Input yin("---\n"
1766             "- 65535\n"
1767             "- 0\n"
1768             "- 66000\n"
1769             "...\n",
1770             /*Ctxt=*/nullptr,
1771             suppressErrorMessages);
1772   yin >> seq;
1773 
1774   EXPECT_TRUE(!!yin.error());
1775 }
1776 
1777 
1778 //
1779 // Test error handling reading built-in uint32_t type
1780 //
1781 LLVM_YAML_IS_SEQUENCE_VECTOR(uint32_t)
TEST(YAMLIO,TestReadBuiltInTypesUint32Error)1782 TEST(YAMLIO, TestReadBuiltInTypesUint32Error) {
1783   std::vector<uint32_t> seq;
1784   Input yin("---\n"
1785             "- 4000000000\n"
1786             "- 0\n"
1787             "- 5000000000\n"
1788             "...\n",
1789             /*Ctxt=*/nullptr,
1790             suppressErrorMessages);
1791   yin >> seq;
1792 
1793   EXPECT_TRUE(!!yin.error());
1794 }
1795 
1796 
1797 //
1798 // Test error handling reading built-in uint64_t type
1799 //
1800 LLVM_YAML_IS_SEQUENCE_VECTOR(uint64_t)
TEST(YAMLIO,TestReadBuiltInTypesUint64Error)1801 TEST(YAMLIO, TestReadBuiltInTypesUint64Error) {
1802   std::vector<uint64_t> seq;
1803   Input yin("---\n"
1804             "- 18446744073709551615\n"
1805             "- 0\n"
1806             "- 19446744073709551615\n"
1807             "...\n",
1808             /*Ctxt=*/nullptr,
1809             suppressErrorMessages);
1810   yin >> seq;
1811 
1812   EXPECT_TRUE(!!yin.error());
1813 }
1814 
1815 
1816 //
1817 // Test error handling reading built-in int8_t type
1818 //
1819 LLVM_YAML_IS_SEQUENCE_VECTOR(int8_t)
TEST(YAMLIO,TestReadBuiltInTypesint8OverError)1820 TEST(YAMLIO, TestReadBuiltInTypesint8OverError) {
1821   std::vector<int8_t> seq;
1822   Input yin("---\n"
1823             "- -128\n"
1824             "- 0\n"
1825             "- 127\n"
1826             "- 128\n"
1827            "...\n",
1828             /*Ctxt=*/nullptr,
1829             suppressErrorMessages);
1830   yin >> seq;
1831 
1832   EXPECT_TRUE(!!yin.error());
1833 }
1834 
1835 //
1836 // Test error handling reading built-in int8_t type
1837 //
TEST(YAMLIO,TestReadBuiltInTypesint8UnderError)1838 TEST(YAMLIO, TestReadBuiltInTypesint8UnderError) {
1839   std::vector<int8_t> seq;
1840   Input yin("---\n"
1841             "- -128\n"
1842             "- 0\n"
1843             "- 127\n"
1844             "- -129\n"
1845             "...\n",
1846             /*Ctxt=*/nullptr,
1847             suppressErrorMessages);
1848   yin >> seq;
1849 
1850   EXPECT_TRUE(!!yin.error());
1851 }
1852 
1853 
1854 //
1855 // Test error handling reading built-in int16_t type
1856 //
1857 LLVM_YAML_IS_SEQUENCE_VECTOR(int16_t)
TEST(YAMLIO,TestReadBuiltInTypesint16UnderError)1858 TEST(YAMLIO, TestReadBuiltInTypesint16UnderError) {
1859   std::vector<int16_t> seq;
1860   Input yin("---\n"
1861             "- 32767\n"
1862             "- 0\n"
1863             "- -32768\n"
1864             "- -32769\n"
1865             "...\n",
1866             /*Ctxt=*/nullptr,
1867             suppressErrorMessages);
1868   yin >> seq;
1869 
1870   EXPECT_TRUE(!!yin.error());
1871 }
1872 
1873 
1874 //
1875 // Test error handling reading built-in int16_t type
1876 //
TEST(YAMLIO,TestReadBuiltInTypesint16OverError)1877 TEST(YAMLIO, TestReadBuiltInTypesint16OverError) {
1878   std::vector<int16_t> seq;
1879   Input yin("---\n"
1880             "- 32767\n"
1881             "- 0\n"
1882             "- -32768\n"
1883             "- 32768\n"
1884             "...\n",
1885             /*Ctxt=*/nullptr,
1886             suppressErrorMessages);
1887   yin >> seq;
1888 
1889   EXPECT_TRUE(!!yin.error());
1890 }
1891 
1892 
1893 //
1894 // Test error handling reading built-in int32_t type
1895 //
1896 LLVM_YAML_IS_SEQUENCE_VECTOR(int32_t)
TEST(YAMLIO,TestReadBuiltInTypesint32UnderError)1897 TEST(YAMLIO, TestReadBuiltInTypesint32UnderError) {
1898   std::vector<int32_t> seq;
1899   Input yin("---\n"
1900             "- 2147483647\n"
1901             "- 0\n"
1902             "- -2147483648\n"
1903             "- -2147483649\n"
1904             "...\n",
1905             /*Ctxt=*/nullptr,
1906             suppressErrorMessages);
1907   yin >> seq;
1908 
1909   EXPECT_TRUE(!!yin.error());
1910 }
1911 
1912 //
1913 // Test error handling reading built-in int32_t type
1914 //
TEST(YAMLIO,TestReadBuiltInTypesint32OverError)1915 TEST(YAMLIO, TestReadBuiltInTypesint32OverError) {
1916   std::vector<int32_t> seq;
1917   Input yin("---\n"
1918             "- 2147483647\n"
1919             "- 0\n"
1920             "- -2147483648\n"
1921             "- 2147483649\n"
1922             "...\n",
1923             /*Ctxt=*/nullptr,
1924             suppressErrorMessages);
1925   yin >> seq;
1926 
1927   EXPECT_TRUE(!!yin.error());
1928 }
1929 
1930 
1931 //
1932 // Test error handling reading built-in int64_t type
1933 //
1934 LLVM_YAML_IS_SEQUENCE_VECTOR(int64_t)
TEST(YAMLIO,TestReadBuiltInTypesint64UnderError)1935 TEST(YAMLIO, TestReadBuiltInTypesint64UnderError) {
1936   std::vector<int64_t> seq;
1937   Input yin("---\n"
1938             "- -9223372036854775808\n"
1939             "- 0\n"
1940             "- 9223372036854775807\n"
1941             "- -9223372036854775809\n"
1942             "...\n",
1943             /*Ctxt=*/nullptr,
1944             suppressErrorMessages);
1945   yin >> seq;
1946 
1947   EXPECT_TRUE(!!yin.error());
1948 }
1949 
1950 //
1951 // Test error handling reading built-in int64_t type
1952 //
TEST(YAMLIO,TestReadBuiltInTypesint64OverError)1953 TEST(YAMLIO, TestReadBuiltInTypesint64OverError) {
1954   std::vector<int64_t> seq;
1955   Input yin("---\n"
1956             "- -9223372036854775808\n"
1957             "- 0\n"
1958             "- 9223372036854775807\n"
1959             "- 9223372036854775809\n"
1960             "...\n",
1961             /*Ctxt=*/nullptr,
1962             suppressErrorMessages);
1963   yin >> seq;
1964 
1965   EXPECT_TRUE(!!yin.error());
1966 }
1967 
1968 //
1969 // Test error handling reading built-in float type
1970 //
1971 LLVM_YAML_IS_SEQUENCE_VECTOR(float)
TEST(YAMLIO,TestReadBuiltInTypesFloatError)1972 TEST(YAMLIO, TestReadBuiltInTypesFloatError) {
1973   std::vector<float> seq;
1974   Input yin("---\n"
1975             "- 0.0\n"
1976             "- 1000.1\n"
1977             "- -123.456\n"
1978             "- 1.2.3\n"
1979             "...\n",
1980             /*Ctxt=*/nullptr,
1981             suppressErrorMessages);
1982   yin >> seq;
1983 
1984   EXPECT_TRUE(!!yin.error());
1985 }
1986 
1987 //
1988 // Test error handling reading built-in float type
1989 //
1990 LLVM_YAML_IS_SEQUENCE_VECTOR(double)
TEST(YAMLIO,TestReadBuiltInTypesDoubleError)1991 TEST(YAMLIO, TestReadBuiltInTypesDoubleError) {
1992   std::vector<double> seq;
1993   Input yin("---\n"
1994             "- 0.0\n"
1995             "- 1000.1\n"
1996             "- -123.456\n"
1997             "- 1.2.3\n"
1998             "...\n",
1999             /*Ctxt=*/nullptr,
2000             suppressErrorMessages);
2001   yin >> seq;
2002 
2003   EXPECT_TRUE(!!yin.error());
2004 }
2005 
2006 //
2007 // Test error handling reading built-in Hex8 type
2008 //
2009 LLVM_YAML_IS_SEQUENCE_VECTOR(Hex8)
TEST(YAMLIO,TestReadBuiltInTypesHex8Error)2010 TEST(YAMLIO, TestReadBuiltInTypesHex8Error) {
2011   std::vector<Hex8> seq;
2012   Input yin("---\n"
2013             "- 0x12\n"
2014             "- 0xFE\n"
2015             "- 0x123\n"
2016             "...\n",
2017             /*Ctxt=*/nullptr,
2018             suppressErrorMessages);
2019   yin >> seq;
2020 
2021   EXPECT_TRUE(!!yin.error());
2022 }
2023 
2024 
2025 //
2026 // Test error handling reading built-in Hex16 type
2027 //
2028 LLVM_YAML_IS_SEQUENCE_VECTOR(Hex16)
TEST(YAMLIO,TestReadBuiltInTypesHex16Error)2029 TEST(YAMLIO, TestReadBuiltInTypesHex16Error) {
2030   std::vector<Hex16> seq;
2031   Input yin("---\n"
2032             "- 0x0012\n"
2033             "- 0xFEFF\n"
2034             "- 0x12345\n"
2035             "...\n",
2036             /*Ctxt=*/nullptr,
2037             suppressErrorMessages);
2038   yin >> seq;
2039 
2040   EXPECT_TRUE(!!yin.error());
2041 }
2042 
2043 //
2044 // Test error handling reading built-in Hex32 type
2045 //
2046 LLVM_YAML_IS_SEQUENCE_VECTOR(Hex32)
TEST(YAMLIO,TestReadBuiltInTypesHex32Error)2047 TEST(YAMLIO, TestReadBuiltInTypesHex32Error) {
2048   std::vector<Hex32> seq;
2049   Input yin("---\n"
2050             "- 0x0012\n"
2051             "- 0xFEFF0000\n"
2052             "- 0x1234556789\n"
2053             "...\n",
2054             /*Ctxt=*/nullptr,
2055             suppressErrorMessages);
2056   yin >> seq;
2057 
2058   EXPECT_TRUE(!!yin.error());
2059 }
2060 
2061 //
2062 // Test error handling reading built-in Hex64 type
2063 //
2064 LLVM_YAML_IS_SEQUENCE_VECTOR(Hex64)
TEST(YAMLIO,TestReadBuiltInTypesHex64Error)2065 TEST(YAMLIO, TestReadBuiltInTypesHex64Error) {
2066   std::vector<Hex64> seq;
2067   Input yin("---\n"
2068             "- 0x0012\n"
2069             "- 0xFFEEDDCCBBAA9988\n"
2070             "- 0x12345567890ABCDEF0\n"
2071             "...\n",
2072             /*Ctxt=*/nullptr,
2073             suppressErrorMessages);
2074   yin >> seq;
2075 
2076   EXPECT_TRUE(!!yin.error());
2077 }
2078 
TEST(YAMLIO,TestMalformedMapFailsGracefully)2079 TEST(YAMLIO, TestMalformedMapFailsGracefully) {
2080   FooBar doc;
2081   {
2082     // We pass the suppressErrorMessages handler to handle the error
2083     // message generated in the constructor of Input.
2084     Input yin("{foo:3, bar: 5}", /*Ctxt=*/nullptr, suppressErrorMessages);
2085     yin >> doc;
2086     EXPECT_TRUE(!!yin.error());
2087   }
2088 
2089   {
2090     Input yin("---\nfoo:3\nbar: 5\n...\n", /*Ctxt=*/nullptr, suppressErrorMessages);
2091     yin >> doc;
2092     EXPECT_TRUE(!!yin.error());
2093   }
2094 }
2095 
2096 struct OptionalTest {
2097   std::vector<int> Numbers;
2098 };
2099 
2100 struct OptionalTestSeq {
2101   std::vector<OptionalTest> Tests;
2102 };
2103 
2104 LLVM_YAML_IS_SEQUENCE_VECTOR(OptionalTest)
2105 namespace llvm {
2106 namespace yaml {
2107   template <>
2108   struct MappingTraits<OptionalTest> {
mappingllvm::yaml::MappingTraits2109     static void mapping(IO& IO, OptionalTest &OT) {
2110       IO.mapOptional("Numbers", OT.Numbers);
2111     }
2112   };
2113 
2114   template <>
2115   struct MappingTraits<OptionalTestSeq> {
mappingllvm::yaml::MappingTraits2116     static void mapping(IO &IO, OptionalTestSeq &OTS) {
2117       IO.mapOptional("Tests", OTS.Tests);
2118     }
2119   };
2120 }
2121 }
2122 
TEST(YAMLIO,SequenceElideTest)2123 TEST(YAMLIO, SequenceElideTest) {
2124   // Test that writing out a purely optional structure with its fields set to
2125   // default followed by other data is properly read back in.
2126   OptionalTestSeq Seq;
2127   OptionalTest One, Two, Three, Four;
2128   int N[] = {1, 2, 3};
2129   Three.Numbers.assign(N, N + 3);
2130   Seq.Tests.push_back(One);
2131   Seq.Tests.push_back(Two);
2132   Seq.Tests.push_back(Three);
2133   Seq.Tests.push_back(Four);
2134 
2135   std::string intermediate;
2136   {
2137     llvm::raw_string_ostream ostr(intermediate);
2138     Output yout(ostr);
2139     yout << Seq;
2140   }
2141 
2142   Input yin(intermediate);
2143   OptionalTestSeq Seq2;
2144   yin >> Seq2;
2145 
2146   EXPECT_FALSE(yin.error());
2147 
2148   EXPECT_EQ(4UL, Seq2.Tests.size());
2149 
2150   EXPECT_TRUE(Seq2.Tests[0].Numbers.empty());
2151   EXPECT_TRUE(Seq2.Tests[1].Numbers.empty());
2152 
2153   EXPECT_EQ(1, Seq2.Tests[2].Numbers[0]);
2154   EXPECT_EQ(2, Seq2.Tests[2].Numbers[1]);
2155   EXPECT_EQ(3, Seq2.Tests[2].Numbers[2]);
2156 
2157   EXPECT_TRUE(Seq2.Tests[3].Numbers.empty());
2158 }
2159 
TEST(YAMLIO,TestEmptyStringFailsForMapWithRequiredFields)2160 TEST(YAMLIO, TestEmptyStringFailsForMapWithRequiredFields) {
2161   FooBar doc;
2162   Input yin("");
2163   yin >> doc;
2164   EXPECT_TRUE(!!yin.error());
2165 }
2166 
TEST(YAMLIO,TestEmptyStringSucceedsForMapWithOptionalFields)2167 TEST(YAMLIO, TestEmptyStringSucceedsForMapWithOptionalFields) {
2168   OptionalTest doc;
2169   Input yin("");
2170   yin >> doc;
2171   EXPECT_FALSE(yin.error());
2172 }
2173 
TEST(YAMLIO,TestEmptyStringSucceedsForSequence)2174 TEST(YAMLIO, TestEmptyStringSucceedsForSequence) {
2175   std::vector<uint8_t> seq;
2176   Input yin("", /*Ctxt=*/nullptr, suppressErrorMessages);
2177   yin >> seq;
2178 
2179   EXPECT_FALSE(yin.error());
2180   EXPECT_TRUE(seq.empty());
2181 }
2182 
2183 struct FlowMap {
2184   llvm::StringRef str1, str2, str3;
FlowMapFlowMap2185   FlowMap(llvm::StringRef str1, llvm::StringRef str2, llvm::StringRef str3)
2186     : str1(str1), str2(str2), str3(str3) {}
2187 };
2188 
2189 struct FlowSeq {
2190   llvm::StringRef str;
FlowSeqFlowSeq2191   FlowSeq(llvm::StringRef S) : str(S) {}
2192   FlowSeq() = default;
2193 };
2194 
2195 namespace llvm {
2196 namespace yaml {
2197   template <>
2198   struct MappingTraits<FlowMap> {
mappingllvm::yaml::MappingTraits2199     static void mapping(IO &io, FlowMap &fm) {
2200       io.mapRequired("str1", fm.str1);
2201       io.mapRequired("str2", fm.str2);
2202       io.mapRequired("str3", fm.str3);
2203     }
2204 
2205     static const bool flow = true;
2206   };
2207 
2208 template <>
2209 struct ScalarTraits<FlowSeq> {
outputllvm::yaml::ScalarTraits2210   static void output(const FlowSeq &value, void*, llvm::raw_ostream &out) {
2211     out << value.str;
2212   }
inputllvm::yaml::ScalarTraits2213   static StringRef input(StringRef scalar, void*, FlowSeq &value) {
2214     value.str = scalar;
2215     return "";
2216   }
2217 
mustQuotellvm::yaml::ScalarTraits2218   static bool mustQuote(StringRef S) { return false; }
2219 };
2220 }
2221 }
2222 
2223 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(FlowSeq)
2224 
TEST(YAMLIO,TestWrapFlow)2225 TEST(YAMLIO, TestWrapFlow) {
2226   std::string out;
2227   llvm::raw_string_ostream ostr(out);
2228   FlowMap Map("This is str1", "This is str2", "This is str3");
2229   std::vector<FlowSeq> Seq;
2230   Seq.emplace_back("This is str1");
2231   Seq.emplace_back("This is str2");
2232   Seq.emplace_back("This is str3");
2233 
2234   {
2235     // 20 is just bellow the total length of the first mapping field.
2236     // We should wreap at every element.
2237     Output yout(ostr, nullptr, 15);
2238 
2239     yout << Map;
2240     ostr.flush();
2241     EXPECT_EQ(out,
2242               "---\n"
2243               "{ str1: This is str1, \n"
2244               "  str2: This is str2, \n"
2245               "  str3: This is str3 }\n"
2246               "...\n");
2247     out.clear();
2248 
2249     yout << Seq;
2250     ostr.flush();
2251     EXPECT_EQ(out,
2252               "---\n"
2253               "[ This is str1, \n"
2254               "  This is str2, \n"
2255               "  This is str3 ]\n"
2256               "...\n");
2257     out.clear();
2258   }
2259   {
2260     // 25 will allow the second field to be output on the first line.
2261     Output yout(ostr, nullptr, 25);
2262 
2263     yout << Map;
2264     ostr.flush();
2265     EXPECT_EQ(out,
2266               "---\n"
2267               "{ str1: This is str1, str2: This is str2, \n"
2268               "  str3: This is str3 }\n"
2269               "...\n");
2270     out.clear();
2271 
2272     yout << Seq;
2273     ostr.flush();
2274     EXPECT_EQ(out,
2275               "---\n"
2276               "[ This is str1, This is str2, \n"
2277               "  This is str3 ]\n"
2278               "...\n");
2279     out.clear();
2280   }
2281   {
2282     // 0 means no wrapping.
2283     Output yout(ostr, nullptr, 0);
2284 
2285     yout << Map;
2286     ostr.flush();
2287     EXPECT_EQ(out,
2288               "---\n"
2289               "{ str1: This is str1, str2: This is str2, str3: This is str3 }\n"
2290               "...\n");
2291     out.clear();
2292 
2293     yout << Seq;
2294     ostr.flush();
2295     EXPECT_EQ(out,
2296               "---\n"
2297               "[ This is str1, This is str2, This is str3 ]\n"
2298               "...\n");
2299     out.clear();
2300   }
2301 }
2302