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