1 2 // Copyright Ferdinand Majerech 2011-2014. 3 // Distributed under the Boost Software License, Version 1.0. 4 // (See accompanying file LICENSE_1_0.txt or copy at 5 // http://www.boost.org/LICENSE_1_0.txt) 6 7 module dyaml.testemitter; 8 9 10 version(unittest) 11 { 12 13 import std.algorithm; 14 import std.file; 15 import std.range; 16 import std.typecons; 17 18 import dyaml.stream; 19 import dyaml.dumper; 20 import dyaml.event; 21 import dyaml.testcommon; 22 import dyaml.token; 23 24 25 /// Determine if events in events1 are equivalent to events in events2. 26 /// 27 /// Params: events1 = First event array to compare. 28 /// events2 = Second event array to compare. 29 /// 30 /// Returns: true if the events are equivalent, false otherwise. 31 bool compareEvents(Event[] events1, Event[] events2) 32 { 33 if(events1.length != events2.length){return false;} 34 35 for(uint e = 0; e < events1.length; ++e) 36 { 37 auto e1 = events1[e]; 38 auto e2 = events2[e]; 39 40 //Different event types. 41 if(e1.id != e2.id){return false;} 42 //Different anchor (if applicable). 43 if([EventID.SequenceStart, 44 EventID.MappingStart, 45 EventID.Alias, 46 EventID.Scalar].canFind(e1.id) 47 && e1.anchor != e2.anchor) 48 { 49 return false; 50 } 51 //Different collection tag (if applicable). 52 if([EventID.SequenceStart, EventID.MappingStart].canFind(e1.id) && e1.tag != e2.tag) 53 { 54 return false; 55 } 56 if(e1.id == EventID.Scalar) 57 { 58 //Different scalar tag (if applicable). 59 if(![e1.implicit, e1.implicit_2, e2.implicit, e2.implicit_2].canFind(true) 60 && e1.tag != e2.tag) 61 { 62 return false; 63 } 64 //Different scalar value. 65 if(e1.value != e2.value) 66 { 67 return false; 68 } 69 } 70 } 71 return true; 72 } 73 74 /// Test emitter by getting events from parsing a file, emitting them, parsing 75 /// the emitted result and comparing events from parsing the emitted result with 76 /// originally parsed events. 77 /// 78 /// Params: verbose = Print verbose output? 79 /// dataFilename = YAML file to parse. 80 /// canonicalFilename = Canonical YAML file used as dummy to determine 81 /// which data files to load. 82 void testEmitterOnData(bool verbose, string dataFilename, string canonicalFilename) 83 { 84 //Must exist due to Anchor, Tags reference counts. 85 auto loader = Loader(dataFilename); 86 auto events = cast(Event[])loader.parse(); 87 auto emitStream = new YMemoryStream; 88 Dumper(emitStream).emit(events); 89 90 if(verbose) 91 { 92 writeln(dataFilename); 93 writeln("ORIGINAL:\n", readText(dataFilename)); 94 writeln("OUTPUT:\n", cast(string)emitStream.data); 95 } 96 97 auto loader2 = Loader(emitStream.data.dup); 98 loader2.name = "TEST"; 99 loader2.constructor = new Constructor; 100 loader2.resolver = new Resolver; 101 auto newEvents = cast(Event[])loader2.parse(); 102 assert(compareEvents(events, newEvents)); 103 } 104 105 /// Test emitter by getting events from parsing a canonical YAML file, emitting 106 /// them both in canonical and normal format, parsing the emitted results and 107 /// comparing events from parsing the emitted result with originally parsed events. 108 /// 109 /// Params: verbose = Print verbose output? 110 /// canonicalFilename = Canonical YAML file to parse. 111 void testEmitterOnCanonical(bool verbose, string canonicalFilename) 112 { 113 //Must exist due to Anchor, Tags reference counts. 114 auto loader = Loader(canonicalFilename); 115 auto events = cast(Event[])loader.parse(); 116 foreach(canonical; [false, true]) 117 { 118 auto emitStream = new YMemoryStream; 119 auto dumper = Dumper(emitStream); 120 dumper.canonical = canonical; 121 dumper.emit(events); 122 if(verbose) 123 { 124 writeln("OUTPUT (canonical=", canonical, "):\n", 125 cast(string)emitStream.data); 126 } 127 auto loader2 = Loader(emitStream.data.dup); 128 loader2.name = "TEST"; 129 loader2.constructor = new Constructor; 130 loader2.resolver = new Resolver; 131 auto newEvents = cast(Event[])loader2.parse(); 132 assert(compareEvents(events, newEvents)); 133 } 134 } 135 136 /// Test emitter by getting events from parsing a file, emitting them with all 137 /// possible scalar and collection styles, parsing the emitted results and 138 /// comparing events from parsing the emitted result with originally parsed events. 139 /// 140 /// Params: verbose = Print verbose output? 141 /// dataFilename = YAML file to parse. 142 /// canonicalFilename = Canonical YAML file used as dummy to determine 143 /// which data files to load. 144 void testEmitterStyles(bool verbose, string dataFilename, string canonicalFilename) 145 { 146 foreach(filename; [dataFilename, canonicalFilename]) 147 { 148 //must exist due to Anchor, Tags reference counts 149 auto loader = Loader(canonicalFilename); 150 auto events = cast(Event[])loader.parse(); 151 foreach(flowStyle; [CollectionStyle.Block, CollectionStyle.Flow]) 152 { 153 foreach(style; [ScalarStyle.Literal, ScalarStyle.Folded, 154 ScalarStyle.DoubleQuoted, ScalarStyle.SingleQuoted, 155 ScalarStyle.Plain]) 156 { 157 Event[] styledEvents; 158 foreach(event; events) 159 { 160 if(event.id == EventID.Scalar) 161 { 162 event = scalarEvent(Mark(), Mark(), event.anchor, event.tag, 163 tuple(event.implicit, event.implicit_2), 164 event.value, style); 165 } 166 else if(event.id == EventID.SequenceStart) 167 { 168 event = sequenceStartEvent(Mark(), Mark(), event.anchor, 169 event.tag, event.implicit, flowStyle); 170 } 171 else if(event.id == EventID.MappingStart) 172 { 173 event = mappingStartEvent(Mark(), Mark(), event.anchor, 174 event.tag, event.implicit, flowStyle); 175 } 176 styledEvents ~= event; 177 } 178 auto emitStream = new YMemoryStream; 179 Dumper(emitStream).emit(styledEvents); 180 if(verbose) 181 { 182 writeln("OUTPUT (", filename, ", ", to!string(flowStyle), ", ", 183 to!string(style), ")"); 184 writeln(emitStream.data); 185 } 186 auto loader2 = Loader(emitStream.data.dup); 187 loader2.name = "TEST"; 188 loader2.constructor = new Constructor; 189 loader2.resolver = new Resolver; 190 auto newEvents = cast(Event[])loader2.parse(); 191 assert(compareEvents(events, newEvents)); 192 } 193 } 194 } 195 } 196 197 unittest 198 { 199 writeln("D:YAML Emitter unittest"); 200 run("testEmitterOnData", &testEmitterOnData, ["data", "canonical"]); 201 run("testEmitterOnCanonical", &testEmitterOnCanonical, ["canonical"]); 202 run("testEmitterStyles", &testEmitterStyles, ["data", "canonical"]); 203 } 204 205 } // version(unittest)