1#include "tests.h"
2#include "yaml-cpp/yaml.h"
3#include <sstream>
4#include <algorithm>
5#include <iostream>
6
7namespace Test
8{
9	namespace Parser {
10		void SimpleScalar(std::string& inputScalar, std::string& desiredOutput)
11		{
12			inputScalar = "Hello, World!";
13			desiredOutput = "Hello, World!";
14		}
15
16		void MultiLineScalar(std::string& inputScalar, std::string& desiredOutput)
17		{
18			inputScalar =
19				"normal scalar, but\n"
20				"over several lines";
21			desiredOutput = "normal scalar, but over several lines";
22		}
23
24		void LiteralScalar(std::string& inputScalar, std::string& desiredOutput)
25		{
26			inputScalar =
27				"|\n"
28				" literal scalar - so we can draw ASCII:\n"
29				" \n"
30                "          -   -\n"
31                "         |  -  |\n"
32                "          -----\n";
33			desiredOutput =
34				"literal scalar - so we can draw ASCII:\n"
35				"\n"
36                "         -   -\n"
37                "        |  -  |\n"
38                "         -----\n";
39		}
40
41		void FoldedScalar(std::string& inputScalar, std::string& desiredOutput)
42		{
43			inputScalar =
44				">\n"
45				" and a folded scalar... so we\n"
46				" can just keep writing various\n"
47				" things. And if we want to keep indentation:\n"
48				" \n"
49				"    we just indent a little\n"
50				"    see, this stays indented";
51			desiredOutput =
52				"and a folded scalar... so we"
53				" can just keep writing various"
54				" things. And if we want to keep indentation:\n"
55				"\n"
56				"   we just indent a little\n"
57				"   see, this stays indented";
58		}
59
60		void ChompedFoldedScalar(std::string& inputScalar, std::string& desiredOutput)
61		{
62			inputScalar =
63				">-\n"
64				"  Here's a folded scalar\n"
65				"  that gets chomped.";
66			desiredOutput =
67				"Here's a folded scalar"
68				" that gets chomped.";
69		}
70
71		void ChompedLiteralScalar(std::string& inputScalar, std::string& desiredOutput)
72		{
73			inputScalar =
74				"|-\n"
75				"  Here's a literal scalar\n"
76				"  that gets chomped.";
77			desiredOutput =
78				"Here's a literal scalar\n"
79				"that gets chomped.";
80		}
81
82		void FoldedScalarWithIndent(std::string& inputScalar, std::string& desiredOutput)
83		{
84			inputScalar =
85				">2\n"
86				"       Here's a folded scalar\n"
87				"  that starts with some indentation.";
88			desiredOutput =
89				"     Here's a folded scalar\n"
90				"that starts with some indentation.";
91		}
92
93		void ColonScalar(std::string& inputScalar, std::string& desiredOutput)
94		{
95			inputScalar = "::vector";
96			desiredOutput = "::vector";
97		}
98
99		void QuotedScalar(std::string& inputScalar, std::string& desiredOutput)
100		{
101			inputScalar = "\": - ()\"";
102			desiredOutput = ": - ()";
103		}
104
105		void CommaScalar(std::string& inputScalar, std::string& desiredOutput)
106		{
107			inputScalar = "Up, up, and away!";
108			desiredOutput = "Up, up, and away!";
109		}
110
111		void DashScalar(std::string& inputScalar, std::string& desiredOutput)
112		{
113			inputScalar = "-123";
114			desiredOutput = "-123";
115		}
116
117		void URLScalar(std::string& inputScalar, std::string& desiredOutput)
118		{
119			inputScalar = "http://example.com/foo#bar";
120			desiredOutput = "http://example.com/foo#bar";
121		}
122
123		bool SimpleSeq()
124		{
125			std::string input =
126				"- eggs\n"
127				"- bread\n"
128				"- milk";
129
130			std::stringstream stream(input);
131			YAML::Parser parser(stream);
132			YAML::Node doc;
133			parser.GetNextDocument(doc);
134
135			std::string output;
136			if(doc[0].to<std::string>() != "eggs")
137				return false;
138			if(doc[1].to<std::string>() != "bread")
139				return false;
140			if(doc[2].to<std::string>() != "milk")
141				return false;
142
143			return true;
144		}
145
146		bool SimpleMap()
147		{
148			std::string input =
149				"name: Prince Fielder\n"
150				"position: 1B\n"
151				"bats: L";
152
153			std::stringstream stream(input);
154			YAML::Parser parser(stream);
155			YAML::Node doc;
156			parser.GetNextDocument(doc);
157
158			std::string output;
159			doc["name"] >> output;
160			if(output != "Prince Fielder")
161				return false;
162			doc["position"] >> output;
163			if(output != "1B")
164				return false;
165			doc["bats"] >> output;
166			if(output != "L")
167				return false;
168
169			return true;
170		}
171
172		bool FlowSeq()
173		{
174			std::string input = "[ 2 , 3, 5  ,  7,   11]";
175
176			std::stringstream stream(input);
177			YAML::Parser parser(stream);
178			YAML::Node doc;
179			parser.GetNextDocument(doc);
180
181			int output;
182			doc[0] >> output;
183			if(output != 2)
184				return false;
185			doc[1] >> output;
186			if(output != 3)
187				return false;
188			doc[2] >> output;
189			if(output != 5)
190				return false;
191			doc[3] >> output;
192			if(output != 7)
193				return false;
194			doc[4] >> output;
195			if(output != 11)
196				return false;
197
198			return true;
199		}
200
201		bool FlowMap()
202		{
203			std::string input = "{hr: 65, avg: 0.278}";
204
205			std::stringstream stream(input);
206			YAML::Parser parser(stream);
207			YAML::Node doc;
208			parser.GetNextDocument(doc);
209
210			std::string output;
211			doc["hr"] >> output;
212			if(output != "65")
213				return false;
214			doc["avg"] >> output;
215			if(output != "0.278")
216				return false;
217
218			return true;
219		}
220
221		bool FlowMapWithOmittedKey()
222		{
223			std::string input = "{: omitted key}";
224			std::stringstream stream(input);
225			YAML::Parser parser(stream);
226			YAML::Node doc;
227			parser.GetNextDocument(doc);
228
229			std::string output;
230			doc[YAML::Null] >> output;
231			if(output != "omitted key")
232				return false;
233
234			return true;
235		}
236
237		bool FlowMapWithOmittedValue()
238		{
239			std::string input = "{a: b, c:, d:}";
240			std::stringstream stream(input);
241			YAML::Parser parser(stream);
242			YAML::Node doc;
243			parser.GetNextDocument(doc);
244
245			std::string output;
246			doc["a"] >> output;
247			if(output != "b")
248				return false;
249			if(!IsNull(doc["c"]))
250				return false;
251			if(!IsNull(doc["d"]))
252				return false;
253
254			return true;
255		}
256
257		bool FlowMapWithSoloEntry()
258		{
259			std::string input = "{a: b, c, d: e}";
260			std::stringstream stream(input);
261			YAML::Parser parser(stream);
262			YAML::Node doc;
263			parser.GetNextDocument(doc);
264
265			std::string output;
266			doc["a"] >> output;
267			if(output != "b")
268				return false;
269			if(!IsNull(doc["c"]))
270				return false;
271			doc["d"] >> output;
272			if(output != "e")
273				return false;
274
275			return true;
276		}
277
278		bool FlowMapEndingWithSoloEntry()
279		{
280			std::string input = "{a: b, c}";
281			std::stringstream stream(input);
282			YAML::Parser parser(stream);
283			YAML::Node doc;
284			parser.GetNextDocument(doc);
285
286			std::string output;
287			doc["a"] >> output;
288			if(output != "b")
289				return false;
290			if(!IsNull(doc["c"]))
291				return false;
292
293			return true;
294		}
295
296		bool QuotedSimpleKeys()
297		{
298			std::string KeyValue[3] = { "\"double\": double\n", "'single': single\n", "plain: plain\n" };
299
300			int perm[3] = { 0, 1, 2 };
301			do {
302				std::string input = KeyValue[perm[0]] + KeyValue[perm[1]] + KeyValue[perm[2]];
303
304				std::stringstream stream(input);
305				YAML::Parser parser(stream);
306				YAML::Node doc;
307				parser.GetNextDocument(doc);
308
309				std::string output;
310				doc["double"] >> output;
311				if(output != "double")
312					return false;
313				doc["single"] >> output;
314				if(output != "single")
315					return false;
316				doc["plain"] >> output;
317				if(output != "plain")
318					return false;
319			} while(std::next_permutation(perm, perm + 3));
320
321			return true;
322		}
323
324		bool CompressedMapAndSeq()
325		{
326			std::string input = "key:\n- one\n- two";
327
328			std::stringstream stream(input);
329			YAML::Parser parser(stream);
330			YAML::Node doc;
331			parser.GetNextDocument(doc);
332
333			const YAML::Node& seq = doc["key"];
334			if(seq.size() != 2)
335				return false;
336
337			std::string output;
338			seq[0] >> output;
339			if(output != "one")
340				return false;
341			seq[1] >> output;
342			if(output != "two")
343				return false;
344
345			return true;
346		}
347
348		bool NullBlockSeqEntry()
349		{
350			std::string input = "- hello\n-\n- world";
351
352			std::stringstream stream(input);
353			YAML::Parser parser(stream);
354			YAML::Node doc;
355			parser.GetNextDocument(doc);
356
357			std::string output;
358			doc[0] >> output;
359			if(output != "hello")
360				return false;
361			if(!IsNull(doc[1]))
362				return false;
363			doc[2] >> output;
364			if(output != "world")
365				return false;
366
367			return true;
368		}
369
370		bool NullBlockMapKey()
371		{
372			std::string input = ": empty key";
373
374			std::stringstream stream(input);
375			YAML::Parser parser(stream);
376			YAML::Node doc;
377			parser.GetNextDocument(doc);
378
379			std::string output;
380			doc[YAML::Null] >> output;
381			if(output != "empty key")
382				return false;
383
384			return true;
385		}
386
387		bool NullBlockMapValue()
388		{
389			std::string input = "empty value:";
390
391			std::stringstream stream(input);
392			YAML::Parser parser(stream);
393			YAML::Node doc;
394			parser.GetNextDocument(doc);
395
396			if(!IsNull(doc["empty value"]))
397				return false;
398
399			return true;
400		}
401
402		bool SimpleAlias()
403		{
404			std::string input = "- &alias test\n- *alias";
405
406			std::stringstream stream(input);
407			YAML::Parser parser(stream);
408			YAML::Node doc;
409			parser.GetNextDocument(doc);
410
411			std::string output;
412			doc[0] >> output;
413			if(output != "test")
414				return false;
415
416			doc[1] >> output;
417			if(output != "test")
418				return false;
419
420			if(doc.size() != 2)
421				return false;
422
423			return true;
424		}
425
426		bool AliasWithNull()
427		{
428			std::string input = "- &alias\n- *alias";
429
430			std::stringstream stream(input);
431			YAML::Parser parser(stream);
432			YAML::Node doc;
433			parser.GetNextDocument(doc);
434
435			if(!IsNull(doc[0]))
436				return false;
437
438			if(!IsNull(doc[1]))
439				return false;
440
441			if(doc.size() != 2)
442				return false;
443
444			return true;
445		}
446
447		bool AnchorInSimpleKey()
448		{
449			std::string input = "- &a b: c\n- *a";
450
451			std::stringstream stream(input);
452			YAML::Parser parser(stream);
453			YAML::Node doc;
454			parser.GetNextDocument(doc);
455
456			if(doc.size() != 2)
457				return false;
458
459			std::string output;
460			doc[0]["b"] >> output;
461			if(output != "c")
462				return false;
463
464			doc[1] >> output;
465			if(output != "b")
466				return false;
467
468			return true;
469		}
470
471		bool AliasAsSimpleKey()
472		{
473			std::string input = "- &a b\n- *a : c";
474
475			std::stringstream stream(input);
476			YAML::Parser parser(stream);
477			YAML::Node doc;
478			parser.GetNextDocument(doc);
479
480			if(doc.size() != 2)
481				return false;
482
483			std::string output;
484			doc[0] >> output;
485			if(output != "b")
486				return false;
487
488			doc[1]["b"] >> output;
489			if(output != "c")
490				return false;
491
492			return true;
493		}
494
495		bool ExplicitDoc()
496		{
497			std::string input = "---\n- one\n- two";
498
499			std::stringstream stream(input);
500			YAML::Parser parser(stream);
501			YAML::Node doc;
502			parser.GetNextDocument(doc);
503
504			if(doc.size() != 2)
505				return false;
506
507			std::string output;
508			doc[0] >> output;
509			if(output != "one")
510				return false;
511			doc[1] >> output;
512			if(output != "two")
513				return false;
514
515			return true;
516		}
517
518		bool MultipleDocs()
519		{
520			std::string input = "---\nname: doc1\n---\nname: doc2";
521
522			std::stringstream stream(input);
523			YAML::Parser parser(stream);
524			YAML::Node doc;
525			parser.GetNextDocument(doc);
526
527			std::string output;
528			doc["name"] >> output;
529			if(output != "doc1")
530				return false;
531
532			if(!parser)
533				return false;
534
535			parser.GetNextDocument(doc);
536			doc["name"] >> output;
537			if(output != "doc2")
538				return false;
539
540			return true;
541		}
542
543		bool ExplicitEndDoc()
544		{
545			std::string input = "- one\n- two\n...\n...";
546
547			std::stringstream stream(input);
548			YAML::Parser parser(stream);
549			YAML::Node doc;
550			parser.GetNextDocument(doc);
551
552			if(doc.size() != 2)
553				return false;
554
555			std::string output;
556			doc[0] >> output;
557			if(output != "one")
558				return false;
559			doc[1] >> output;
560			if(output != "two")
561				return false;
562
563			return true;
564		}
565
566		bool MultipleDocsWithSomeExplicitIndicators()
567		{
568			std::string input =
569				"- one\n- two\n...\n"
570				"---\nkey: value\n...\n...\n"
571				"- three\n- four\n"
572				"---\nkey: value";
573
574			std::stringstream stream(input);
575			YAML::Parser parser(stream);
576			YAML::Node doc;
577			std::string output;
578
579			parser.GetNextDocument(doc);
580			if(doc.size() != 2)
581				return false;
582			doc[0] >> output;
583			if(output != "one")
584				return false;
585			doc[1] >> output;
586			if(output != "two")
587				return false;
588
589			parser.GetNextDocument(doc);
590			doc["key"] >> output;
591			if(output != "value")
592				return false;
593
594			parser.GetNextDocument(doc);
595			if(doc.size() != 2)
596				return false;
597			doc[0] >> output;
598			if(output != "three")
599				return false;
600			doc[1] >> output;
601			if(output != "four")
602				return false;
603
604			parser.GetNextDocument(doc);
605			doc["key"] >> output;
606			if(output != "value")
607				return false;
608
609			return true;
610		}
611
612		bool BlockKeyWithNullValue()
613		{
614			std::string input =
615				"key:\n"
616				"just a key: value";
617
618			std::stringstream stream(input);
619			YAML::Parser parser(stream);
620			YAML::Node doc;
621
622			parser.GetNextDocument(doc);
623			if(doc.size() != 2)
624				return false;
625			if(!IsNull(doc["key"]))
626			   return false;
627			if(doc["just a key"].to<std::string>() != "value")
628				return false;
629
630			return true;
631		}
632
633		bool Bases()
634		{
635			std::string input =
636				"- 15\n"
637				"- 0x10\n"
638				"- 030\n"
639				"- 0xffffffff\n";
640
641			std::stringstream stream(input);
642			YAML::Parser parser(stream);
643			YAML::Node doc;
644
645			parser.GetNextDocument(doc);
646			if(doc.size() != 4)
647				return false;
648			if(doc[0].to<int>() != 15)
649				return false;
650			if(doc[1].to<int>() != 0x10)
651				return false;
652			if(doc[2].to<int>() != 030)
653				return false;
654			if(doc[3].to<unsigned>() != 0xffffffff)
655				return false;
656			return true;
657		}
658
659		bool KeyNotFound()
660		{
661			std::string input = "key: value";
662			std::stringstream stream(input);
663			YAML::Parser parser(stream);
664			YAML::Node doc;
665			parser.GetNextDocument(doc);
666
667			try {
668				doc["bad key"];
669			} catch(const YAML::Exception& e) {
670				if(e.msg != std::string(YAML::ErrorMsg::KEY_NOT_FOUND) + ": bad key")
671					throw;
672			}
673
674			try {
675				doc[5];
676			} catch(const YAML::Exception& e) {
677				if(e.msg != std::string(YAML::ErrorMsg::KEY_NOT_FOUND) + ": 5")
678					throw;
679			}
680
681			try {
682				doc[2.5];
683			} catch(const YAML::Exception& e) {
684				if(e.msg != std::string(YAML::ErrorMsg::KEY_NOT_FOUND) + ": 2.5")
685					throw;
686			}
687
688			return true;
689		}
690
691		bool DuplicateKey()
692		{
693			std::string input = "{a: 1, b: 2, c: 3, a: 4}";
694			std::stringstream stream(input);
695			YAML::Parser parser(stream);
696			YAML::Node doc;
697			parser.GetNextDocument(doc);
698
699			if(doc["a"].to<int>() != 4)
700				return false;
701			if(doc["b"].to<int>() != 2)
702				return false;
703			if(doc["c"].to<int>() != 3)
704				return false;
705			return true;
706		}
707
708		void PrepareNodeForTagExam(YAML::Node& doc, const std::string& input)
709		{
710			std::stringstream stream(input);
711			YAML::Parser parser(stream);
712			parser.GetNextDocument(doc);
713		}
714
715		struct TagMismatch: public std::exception {
716			TagMismatch(const std::string& actualTag, const std::string& expectedTag) {
717				std::stringstream output;
718				output << "Tag has value \"" << actualTag << "\" but \"" << expectedTag << "\" was expected";
719				what_ = output.str();
720			}
721			virtual ~TagMismatch() throw() {}
722			virtual const char *what() const throw() { return what_.c_str(); }
723
724		private:
725			std::string what_;
726		};
727
728		bool ExpectedTagValue(YAML::Node& node, const char* tag)
729		{
730			if(node.Tag() == tag)
731			  return true;
732
733			throw TagMismatch(node.Tag(), tag);
734		}
735
736		bool DefaultPlainScalarTag()
737		{
738			YAML::Node node;
739			PrepareNodeForTagExam(node, "--- 12");
740
741			return ExpectedTagValue(node, "?");
742		}
743
744		bool DefaultSingleQuotedScalarTag()
745		{
746			YAML::Node node;
747			PrepareNodeForTagExam(node, "--- '12'");
748
749			return ExpectedTagValue(node, "!");
750		}
751
752		bool ExplicitNonSpecificPlainScalarTag()
753		{
754			YAML::Node node;
755			PrepareNodeForTagExam(node, "--- ! 12");
756
757			return ExpectedTagValue(node, "!");
758		}
759
760		bool BasicLocalTag()
761		{
762			YAML::Node node;
763			PrepareNodeForTagExam(node, "--- !foo 12");
764
765			return ExpectedTagValue(node, "!foo");
766		}
767
768		bool VerbatimLocalTag()
769		{
770			YAML::Node node;
771			PrepareNodeForTagExam(node, "--- !<!foo> 12");
772
773			return ExpectedTagValue(node, "!foo");
774		}
775
776		bool StandardShortcutTag()
777		{
778			YAML::Node node;
779			PrepareNodeForTagExam(node, "--- !!int 12");
780
781			return ExpectedTagValue(node, "tag:yaml.org,2002:int");
782		}
783
784		bool VerbatimURITag()
785		{
786			YAML::Node node;
787			PrepareNodeForTagExam(node, "--- !<tag:yaml.org,2002:int> 12");
788
789			return ExpectedTagValue(node, "tag:yaml.org,2002:int");
790		}
791
792		bool DefaultSequenceTag()
793		{
794			YAML::Node node;
795			PrepareNodeForTagExam(node, "--- [12]");
796
797			return ExpectedTagValue(node, "?");
798		}
799
800		bool ExplicitNonSpecificSequenceTag()
801		{
802			YAML::Node node;
803			PrepareNodeForTagExam(node, "--- ! [12]");
804
805			return ExpectedTagValue(node, "!");
806		}
807
808		bool Infinity()
809		{
810			std::string input =
811			"- .inf\n"
812			"- .Inf\n"
813			"- .INF\n"
814			"- +.inf\n"
815			"- +.Inf\n"
816			"- +.INF\n"
817			"- -.inf\n"
818			"- -.Inf\n"
819			"- -.INF\n";
820			std::stringstream stream(input);
821			YAML::Parser parser(stream);
822			YAML::Node doc;
823			parser.GetNextDocument(doc);
824
825			for(unsigned i=0;i<doc.size();i++)
826				if(doc[i].to<double>() != (i < 6 ? +1 : -1) * std::numeric_limits<double>::infinity())
827					return false;
828			for(unsigned i=0;i<doc.size();i++)
829				if(doc[i].to<long double>() != (i < 6 ? +1 : -1) * std::numeric_limits<long double>::infinity())
830					return false;
831			for(unsigned i=0;i<doc.size();i++)
832				if(doc[i].to<float>() != (i < 6 ? +1 : -1) * std::numeric_limits<float>::infinity())
833					return false;
834			return true;
835		}
836
837		bool NaN()
838		{
839			std::string input =
840			"- .nan\n"
841			"- .NaN\n"
842			"- .NAN\n";
843			std::stringstream stream(input);
844			YAML::Parser parser(stream);
845			YAML::Node doc;
846			parser.GetNextDocument(doc);
847
848			for(unsigned i=0;i<doc.size();i++) {
849				double d;
850				doc[i] >> d;
851				if(d == d)
852					return false;
853			}
854			for(unsigned i=0;i<doc.size();i++) {
855				long double d;
856				doc[i] >> d;
857				if(d == d)
858					return false;
859			}
860			for(unsigned i=0;i<doc.size();i++) {
861				float d;
862				doc[i] >> d;
863				if(d == d)
864					return false;
865			}
866			return true;
867		}
868
869		bool NonConstKey()
870		{
871			std::string input = "{a: 1}";
872			std::stringstream stream(input);
873			YAML::Parser parser(stream);
874			YAML::Node doc;
875			parser.GetNextDocument(doc);
876
877			std::vector<char> key(2);
878			key[0] = 'a';
879			key[1] = '\0';
880			if(doc[&key[0]].to<int>() != 1)
881				return false;
882			return true;
883		}
884
885		bool SingleChar()
886		{
887			std::string input = "5";
888			std::stringstream stream(input);
889			YAML::Parser parser(stream);
890			YAML::Node doc;
891			parser.GetNextDocument(doc);
892
893			return doc.to<int>() == 5;
894		}
895
896        bool QuotedNewline()
897        {
898            std::string input = "foo: \"\\n\"";
899			std::stringstream stream(input);
900			YAML::Parser parser(stream);
901			YAML::Node doc;
902			parser.GetNextDocument(doc);
903
904			return doc["foo"].to<std::string>() == "\n";
905        }
906
907        bool DoubleAsInt()
908		{
909			std::string input = "1.5";
910			std::stringstream stream(input);
911			YAML::Parser parser(stream);
912			YAML::Node doc;
913			parser.GetNextDocument(doc);
914
915            try {
916                doc.to<int>();
917            } catch(const YAML::InvalidScalar& e) {
918                return true;
919            }
920
921            return false;
922		}
923
924        bool Binary()
925        {
926            std::string input = "[!!binary \"SGVsbG8sIFdvcmxkIQ==\", !!binary \"TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGludWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4K\"]";
927			std::stringstream stream(input);
928			YAML::Parser parser(stream);
929			YAML::Node doc;
930			parser.GetNextDocument(doc);
931
932            if(doc[0].to<YAML::Binary>() != YAML::Binary(reinterpret_cast<const unsigned char*>("Hello, World!"), 13))
933                return false;
934            if(doc[1].to<YAML::Binary>() != YAML::Binary(reinterpret_cast<const unsigned char*>("Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure.\n"), 270))
935                return false;
936            return true;
937        }
938    }
939
940	namespace {
941		void RunScalarParserTest(void (*test)(std::string&, std::string&), const std::string& name, int& passed, int& total) {
942			std::string error;
943			std::string inputScalar, desiredOutput;
944			std::string output;
945			bool ok = true;
946			try {
947				test(inputScalar, desiredOutput);
948				std::stringstream stream(inputScalar);
949				YAML::Parser parser(stream);
950				YAML::Node doc;
951				parser.GetNextDocument(doc);
952				doc >> output;
953			} catch(const YAML::Exception& e) {
954				ok = false;
955				error = e.what();
956			}
957			if(ok && output == desiredOutput) {
958				passed++;
959			} else {
960				std::cout << "Parser test failed: " << name << "\n";
961				if(error != "")
962					std::cout << "Caught exception: " << error << "\n";
963				else {
964					std::cout << "Output:\n" << output << "<<<\n";
965					std::cout << "Desired output:\n" << desiredOutput << "<<<\n";
966				}
967			}
968			total++;
969		}
970
971		void RunParserTest(bool (*test)(), const std::string& name, int& passed, int& total) {
972			std::string error;
973			bool ok = true;
974			try {
975				ok = test();
976			} catch(const YAML::Exception& e) {
977				ok = false;
978				error = e.what();
979			} catch(const Parser::TagMismatch& e) {
980				ok = false;
981				error = e.what();
982			}
983			if(ok) {
984				passed++;
985			} else {
986				std::cout << "Parser test failed: " << name << "\n";
987				if(error != "")
988					std::cout << "  Caught exception: " << error << "\n";
989			}
990			total++;
991		}
992
993		typedef void (*EncodingFn)(std::ostream&, int);
994
995		inline char Byte(int ch)
996		{
997			return static_cast<char>(static_cast<unsigned char>(static_cast<unsigned int>(ch)));
998		}
999
1000		void EncodeToUtf8(std::ostream& stream, int ch)
1001		{
1002			if (ch <= 0x7F)
1003			{
1004				stream << Byte(ch);
1005			}
1006			else if (ch <= 0x7FF)
1007			{
1008				stream << Byte(0xC0 | (ch >> 6));
1009				stream << Byte(0x80 | (ch & 0x3F));
1010			}
1011			else if (ch <= 0xFFFF)
1012			{
1013				stream << Byte(0xE0 | (ch >> 12));
1014				stream << Byte(0x80 | ((ch >> 6) & 0x3F));
1015				stream << Byte(0x80 | (ch & 0x3F));
1016			}
1017			else if (ch <= 0x1FFFFF)
1018			{
1019				stream << Byte(0xF0 | (ch >> 18));
1020				stream << Byte(0x80 | ((ch >> 12) & 0x3F));
1021				stream << Byte(0x80 | ((ch >> 6) & 0x3F));
1022				stream << Byte(0x80 | (ch & 0x3F));
1023			}
1024		}
1025
1026		bool SplitUtf16HighChar(std::ostream& stream, EncodingFn encoding, int ch)
1027		{
1028			int biasedValue = ch - 0x10000;
1029			if (biasedValue < 0)
1030			{
1031				return false;
1032			}
1033			int high = 0xD800 | (biasedValue >> 10);
1034			int low  = 0xDC00 | (biasedValue & 0x3FF);
1035			encoding(stream, high);
1036			encoding(stream, low);
1037			return true;
1038		}
1039
1040		void EncodeToUtf16LE(std::ostream& stream, int ch)
1041		{
1042			if (!SplitUtf16HighChar(stream, &EncodeToUtf16LE, ch))
1043			{
1044				stream << Byte(ch & 0xFF) << Byte(ch >> 8);
1045			}
1046		}
1047
1048		void EncodeToUtf16BE(std::ostream& stream, int ch)
1049		{
1050			if (!SplitUtf16HighChar(stream, &EncodeToUtf16BE, ch))
1051			{
1052				stream << Byte(ch >> 8) << Byte(ch & 0xFF);
1053			}
1054		}
1055
1056		void EncodeToUtf32LE(std::ostream& stream, int ch)
1057		{
1058			stream << Byte(ch & 0xFF) << Byte((ch >> 8) & 0xFF)
1059				<< Byte((ch >> 16) & 0xFF) << Byte((ch >> 24) & 0xFF);
1060		}
1061
1062		void EncodeToUtf32BE(std::ostream& stream, int ch)
1063		{
1064			stream << Byte((ch >> 24) & 0xFF) << Byte((ch >> 16) & 0xFF)
1065				<< Byte((ch >> 8) & 0xFF) << Byte(ch & 0xFF);
1066		}
1067
1068		class EncodingTester
1069		{
1070		public:
1071			EncodingTester(EncodingFn encoding, bool declareEncoding)
1072			{
1073				if (declareEncoding)
1074				{
1075					encoding(m_yaml, 0xFEFF);
1076				}
1077
1078				AddEntry(encoding, 0x0021, 0x007E); // Basic Latin
1079				AddEntry(encoding, 0x00A1, 0x00FF); // Latin-1 Supplement
1080				AddEntry(encoding, 0x0660, 0x06FF); // Arabic (largest contiguous block)
1081
1082				// CJK unified ideographs (multiple lines)
1083				AddEntry(encoding, 0x4E00, 0x4EFF);
1084				AddEntry(encoding, 0x4F00, 0x4FFF);
1085				AddEntry(encoding, 0x5000, 0x51FF); // 512 character line
1086				AddEntry(encoding, 0x5200, 0x54FF); // 768 character line
1087				AddEntry(encoding, 0x5500, 0x58FF); // 1024 character line
1088
1089				AddEntry(encoding, 0x103A0, 0x103C3); // Old Persian
1090
1091				m_yaml.seekg(0, std::ios::beg);
1092			}
1093
1094			std::istream& stream() {return m_yaml;}
1095			const std::vector<std::string>& entries() {return m_entries;}
1096
1097		private:
1098			std::stringstream m_yaml;
1099			std::vector<std::string> m_entries;
1100
1101			void AddEntry(EncodingFn encoding, int startCh, int endCh)
1102			{
1103				encoding(m_yaml, '-');
1104				encoding(m_yaml, ' ');
1105				encoding(m_yaml, '|');
1106				encoding(m_yaml, '\n');
1107				encoding(m_yaml, ' ');
1108				encoding(m_yaml, ' ');
1109
1110				std::stringstream entry;
1111				for (int ch = startCh; ch <= endCh; ++ch)
1112				{
1113					encoding(m_yaml, ch);
1114					EncodeToUtf8(entry, ch);
1115				}
1116				encoding(m_yaml, '\n');
1117
1118				m_entries.push_back(entry.str());
1119			}
1120		};
1121
1122		void RunEncodingTest(EncodingFn encoding, bool declareEncoding, const std::string& name, int& passed, int& total)
1123		{
1124			EncodingTester tester(encoding, declareEncoding);
1125			std::string error;
1126			bool ok = true;
1127			try {
1128				YAML::Parser parser(tester.stream());
1129				YAML::Node doc;
1130				parser.GetNextDocument(doc);
1131
1132				YAML::Iterator itNode = doc.begin();
1133				std::vector<std::string>::const_iterator itEntry = tester.entries().begin();
1134				for (; (itNode != doc.end()) && (itEntry != tester.entries().end()); ++itNode, ++itEntry)
1135				{
1136					std::string stScalarValue;
1137					if (!itNode->GetScalar(stScalarValue) && (stScalarValue == *itEntry))
1138					{
1139						break;
1140					}
1141				}
1142
1143				if ((itNode != doc.end()) || (itEntry != tester.entries().end()))
1144				{
1145					ok = false;
1146				}
1147			} catch(const YAML::Exception& e) {
1148				ok = false;
1149				error = e.msg;
1150			}
1151			if(ok) {
1152				passed++;
1153			} else {
1154				std::cout << "Parser test failed: " << name << "\n";
1155				if(error != "")
1156					std::cout << "  Caught exception: " << error << "\n";
1157			}
1158			total++;
1159		}
1160	}
1161
1162	bool RunParserTests()
1163	{
1164		int passed = 0;
1165		int total = 0;
1166		RunScalarParserTest(&Parser::SimpleScalar, "simple scalar", passed, total);
1167		RunScalarParserTest(&Parser::MultiLineScalar, "multi-line scalar", passed, total);
1168		RunScalarParserTest(&Parser::LiteralScalar, "literal scalar", passed, total);
1169		RunScalarParserTest(&Parser::FoldedScalar, "folded scalar", passed, total);
1170		RunScalarParserTest(&Parser::ChompedFoldedScalar, "chomped folded scalar", passed, total);
1171		RunScalarParserTest(&Parser::ChompedLiteralScalar, "chomped literal scalar", passed, total);
1172		RunScalarParserTest(&Parser::FoldedScalarWithIndent, "folded scalar with indent", passed, total);
1173		RunScalarParserTest(&Parser::ColonScalar, "colon scalar", passed, total);
1174		RunScalarParserTest(&Parser::QuotedScalar, "quoted scalar", passed, total);
1175		RunScalarParserTest(&Parser::CommaScalar, "comma scalar", passed, total);
1176		RunScalarParserTest(&Parser::DashScalar, "dash scalar", passed, total);
1177		RunScalarParserTest(&Parser::URLScalar, "url scalar", passed, total);
1178
1179		RunParserTest(&Parser::SimpleSeq, "simple seq", passed, total);
1180		RunParserTest(&Parser::SimpleMap, "simple map", passed, total);
1181		RunParserTest(&Parser::FlowSeq, "flow seq", passed, total);
1182		RunParserTest(&Parser::FlowMap, "flow map", passed, total);
1183		RunParserTest(&Parser::FlowMapWithOmittedKey, "flow map with omitted key", passed, total);
1184		RunParserTest(&Parser::FlowMapWithOmittedValue, "flow map with omitted value", passed, total);
1185		RunParserTest(&Parser::FlowMapWithSoloEntry, "flow map with solo entry", passed, total);
1186		RunParserTest(&Parser::FlowMapEndingWithSoloEntry, "flow map ending with solo entry", passed, total);
1187		RunParserTest(&Parser::QuotedSimpleKeys, "quoted simple keys", passed, total);
1188		RunParserTest(&Parser::CompressedMapAndSeq, "compressed map and seq", passed, total);
1189		RunParserTest(&Parser::NullBlockSeqEntry, "null block seq entry", passed, total);
1190		RunParserTest(&Parser::NullBlockMapKey, "null block map key", passed, total);
1191		RunParserTest(&Parser::NullBlockMapValue, "null block map value", passed, total);
1192		RunParserTest(&Parser::SimpleAlias, "simple alias", passed, total);
1193		RunParserTest(&Parser::AliasWithNull, "alias with null", passed, total);
1194		RunParserTest(&Parser::AnchorInSimpleKey, "anchor in simple key", passed, total);
1195		RunParserTest(&Parser::AliasAsSimpleKey, "alias as simple key", passed, total);
1196		RunParserTest(&Parser::ExplicitDoc, "explicit doc", passed, total);
1197		RunParserTest(&Parser::MultipleDocs, "multiple docs", passed, total);
1198		RunParserTest(&Parser::ExplicitEndDoc, "explicit end doc", passed, total);
1199		RunParserTest(&Parser::MultipleDocsWithSomeExplicitIndicators, "multiple docs with some explicit indicators", passed, total);
1200		RunParserTest(&Parser::BlockKeyWithNullValue, "block key with null value", passed, total);
1201		RunParserTest(&Parser::Bases, "bases", passed, total);
1202		RunParserTest(&Parser::KeyNotFound, "key not found", passed, total);
1203		RunParserTest(&Parser::DuplicateKey, "duplicate key", passed, total);
1204		RunParserTest(&Parser::DefaultPlainScalarTag, "default plain scalar tag", passed, total);
1205		RunParserTest(&Parser::DefaultSingleQuotedScalarTag, "default single-quoted scalar tag", passed, total);
1206		RunParserTest(&Parser::ExplicitNonSpecificPlainScalarTag, "explicit, non-specific plain scalar tag", passed, total);
1207		RunParserTest(&Parser::BasicLocalTag, "basic local tag", passed, total);
1208		RunParserTest(&Parser::VerbatimLocalTag, "verbatim local tag", passed, total);
1209		RunParserTest(&Parser::StandardShortcutTag, "standard shortcut tag", passed, total);
1210		RunParserTest(&Parser::VerbatimURITag, "verbatim URI tag", passed, total);
1211		RunParserTest(&Parser::DefaultPlainScalarTag, "default plain scalar tag", passed, total);
1212		RunParserTest(&Parser::DefaultSequenceTag, "default sequence tag", passed, total);
1213		RunParserTest(&Parser::ExplicitNonSpecificSequenceTag, "explicit, non-specific sequence tag", passed, total);
1214		RunParserTest(&Parser::Infinity, "infinity", passed, total);
1215		RunParserTest(&Parser::NaN, "NaN", passed, total);
1216		RunParserTest(&Parser::NonConstKey, "non const key", passed, total);
1217		RunParserTest(&Parser::SingleChar, "single char", passed, total);
1218		RunParserTest(&Parser::QuotedNewline, "quoted newline", passed, total);
1219		RunParserTest(&Parser::DoubleAsInt, "double as int", passed, total);
1220		RunParserTest(&Parser::Binary, "binary", passed, total);
1221
1222		RunEncodingTest(&EncodeToUtf8, false, "UTF-8, no BOM", passed, total);
1223		RunEncodingTest(&EncodeToUtf8, true, "UTF-8 with BOM", passed, total);
1224		RunEncodingTest(&EncodeToUtf16LE, false, "UTF-16LE, no BOM", passed, total);
1225		RunEncodingTest(&EncodeToUtf16LE, true, "UTF-16LE with BOM", passed, total);
1226		RunEncodingTest(&EncodeToUtf16BE, false, "UTF-16BE, no BOM", passed, total);
1227		RunEncodingTest(&EncodeToUtf16BE, true, "UTF-16BE with BOM", passed, total);
1228		RunEncodingTest(&EncodeToUtf32LE, false, "UTF-32LE, no BOM", passed, total);
1229		RunEncodingTest(&EncodeToUtf32LE, true, "UTF-32LE with BOM", passed, total);
1230		RunEncodingTest(&EncodeToUtf32BE, false, "UTF-32BE, no BOM", passed, total);
1231		RunEncodingTest(&EncodeToUtf32BE, true, "UTF-32BE with BOM", passed, total);
1232
1233		std::cout << "Parser tests: " << passed << "/" << total << " passed\n";
1234		return passed == total;
1235	}
1236}
1237
1238