1/**
2 * Copyright (c) 2008, http://www.snakeyaml.org
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.pyyaml;
17
18import java.io.File;
19import java.io.FileInputStream;
20import java.io.InputStream;
21import java.io.Reader;
22import java.util.ArrayList;
23import java.util.Iterator;
24import java.util.List;
25
26import org.yaml.snakeyaml.Yaml;
27import org.yaml.snakeyaml.composer.Composer;
28import org.yaml.snakeyaml.constructor.AbstractConstruct;
29import org.yaml.snakeyaml.constructor.Constructor;
30import org.yaml.snakeyaml.events.AliasEvent;
31import org.yaml.snakeyaml.events.CollectionStartEvent;
32import org.yaml.snakeyaml.events.Event;
33import org.yaml.snakeyaml.events.ScalarEvent;
34import org.yaml.snakeyaml.nodes.MappingNode;
35import org.yaml.snakeyaml.nodes.Node;
36import org.yaml.snakeyaml.nodes.NodeTuple;
37import org.yaml.snakeyaml.nodes.ScalarNode;
38import org.yaml.snakeyaml.nodes.SequenceNode;
39import org.yaml.snakeyaml.parser.ParserImpl;
40import org.yaml.snakeyaml.reader.StreamReader;
41import org.yaml.snakeyaml.reader.UnicodeReader;
42import org.yaml.snakeyaml.resolver.Resolver;
43
44/**
45 * imported from PyYAML
46 */
47public class PyStructureTest extends PyImportTest {
48
49    private void compareEvents(List<Event> events1, List<Event> events2, boolean full) {
50        assertEquals(events1.size(), events2.size());
51        Iterator<Event> iter1 = events1.iterator();
52        Iterator<Event> iter2 = events2.iterator();
53        while (iter1.hasNext()) {
54            Event event1 = iter1.next();
55            Event event2 = iter2.next();
56            assertEquals(event1.getClass(), event2.getClass());
57            if (event1 instanceof AliasEvent && full) {
58                assertEquals(((AliasEvent) event1).getAnchor(), ((AliasEvent) event2).getAnchor());
59            }
60            if (event1 instanceof CollectionStartEvent) {
61                String tag1 = ((CollectionStartEvent) event1).getTag();
62                String tag2 = ((CollectionStartEvent) event1).getTag();
63                if (tag1 != null && !"!".equals(tag1) && tag2 != null && !"!".equals(tag1)) {
64                    assertEquals(tag1, tag2);
65                }
66            }
67            if (event1 instanceof ScalarEvent) {
68                ScalarEvent scalar1 = (ScalarEvent) event1;
69                ScalarEvent scalar2 = (ScalarEvent) event2;
70                if (scalar1.getImplicit().bothFalse() && scalar2.getImplicit().bothFalse()) {
71                    assertEquals(scalar1.getTag(), scalar2.getTag());
72                }
73                assertEquals(scalar1.getValue(), scalar2.getValue());
74            }
75        }
76    }
77
78    public void testParser() {
79        File[] files = getStreamsByExtension(".data", true);
80        assertTrue("No test files found.", files.length > 0);
81        for (File file : files) {
82            if (!file.getName().contains("scan-line-b")) {
83                continue;
84            }
85            try {
86                InputStream input = new FileInputStream(file);
87                List<Event> events1 = parse(input);
88                input.close();
89                assertFalse(events1.isEmpty());
90                int index = file.getAbsolutePath().lastIndexOf('.');
91                String canonicalName = file.getAbsolutePath().substring(0, index) + ".canonical";
92                File canonical = new File(canonicalName);
93                List<Event> events2 = canonicalParse(new FileInputStream(canonical));
94                assertFalse(events2.isEmpty());
95                compareEvents(events1, events2, false);
96            } catch (Exception e) {
97                System.out.println("Failed File: " + file);
98                // fail("Failed File: " + file + "; " + e.getMessage());
99                throw new RuntimeException(e);
100            }
101        }
102    }
103
104    public void testParserOnCanonical() {
105        File[] canonicalFiles = getStreamsByExtension(".canonical", false);
106        assertTrue("No test files found.", canonicalFiles.length > 0);
107        for (File file : canonicalFiles) {
108            try {
109                InputStream input = new FileInputStream(file);
110                List<Event> events1 = parse(input);
111                input.close();
112                assertFalse(events1.isEmpty());
113                List<Event> events2 = canonicalParse(new FileInputStream(file));
114                assertFalse(events2.isEmpty());
115                compareEvents(events1, events2, true);
116            } catch (Exception e) {
117                System.out.println("Failed File: " + file);
118                // fail("Failed File: " + file + "; " + e.getMessage());
119                throw new RuntimeException(e);
120            }
121        }
122    }
123
124    private void compareNodes(Node node1, Node node2) {
125        assertEquals(node1.getClass(), node2.getClass());
126        if (node1 instanceof ScalarNode) {
127            ScalarNode scalar1 = (ScalarNode) node1;
128            ScalarNode scalar2 = (ScalarNode) node2;
129            assertEquals(scalar1.getTag(), scalar2.getTag());
130            assertEquals(scalar1.getValue(), scalar2.getValue());
131        } else {
132            if (node1 instanceof SequenceNode) {
133                SequenceNode seq1 = (SequenceNode) node1;
134                SequenceNode seq2 = (SequenceNode) node2;
135                assertEquals(seq1.getTag(), seq2.getTag());
136                assertEquals(seq1.getValue().size(), seq2.getValue().size());
137                Iterator<Node> iter2 = seq2.getValue().iterator();
138                for (Node child1 : seq1.getValue()) {
139                    Node child2 = iter2.next();
140                    compareNodes(child1, child2);
141                }
142            } else {
143                MappingNode seq1 = (MappingNode) node1;
144                MappingNode seq2 = (MappingNode) node2;
145                assertEquals(seq1.getTag(), seq2.getTag());
146                assertEquals(seq1.getValue().size(), seq2.getValue().size());
147                Iterator<NodeTuple> iter2 = seq2.getValue().iterator();
148                for (NodeTuple child1 : seq1.getValue()) {
149                    NodeTuple child2 = iter2.next();
150                    compareNodes(child1.getKeyNode(), child2.getKeyNode());
151                    compareNodes(child1.getValueNode(), child2.getValueNode());
152                }
153            }
154        }
155    }
156
157    public void testComposer() {
158        File[] files = getStreamsByExtension(".data", true);
159        assertTrue("No test files found.", files.length > 0);
160        for (File file : files) {
161            try {
162                InputStream input = new FileInputStream(file);
163                List<Node> events1 = compose_all(input);
164                input.close();
165                int index = file.getAbsolutePath().lastIndexOf('.');
166                String canonicalName = file.getAbsolutePath().substring(0, index) + ".canonical";
167                File canonical = new File(canonicalName);
168                InputStream input2 = new FileInputStream(canonical);
169                List<Node> events2 = canonical_compose_all(input2);
170                input2.close();
171                assertEquals(events1.size(), events2.size());
172                Iterator<Node> iter1 = events1.iterator();
173                Iterator<Node> iter2 = events2.iterator();
174                while (iter1.hasNext()) {
175                    compareNodes(iter1.next(), iter2.next());
176                }
177            } catch (Exception e) {
178                System.out.println("Failed File: " + file);
179                // fail("Failed File: " + file + "; " + e.getMessage());
180                throw new RuntimeException(e);
181            }
182        }
183    }
184
185    private List<Node> compose_all(InputStream file) {
186        Composer composer = new Composer(new ParserImpl(new StreamReader(new UnicodeReader(file))),
187                new Resolver());
188        List<Node> documents = new ArrayList<Node>();
189        while (composer.checkNode()) {
190            documents.add(composer.getNode());
191        }
192        return documents;
193    }
194
195    private List<Node> canonical_compose_all(InputStream file) {
196        StreamReader reader = new StreamReader(new UnicodeReader(file));
197        StringBuilder buffer = new StringBuilder();
198        while (reader.peek() != '\0') {
199            buffer.append(reader.peek());
200            reader.forward();
201        }
202        CanonicalParser parser = new CanonicalParser(buffer.toString());
203        Composer composer = new Composer(parser, new Resolver());
204        List<Node> documents = new ArrayList<Node>();
205        while (composer.checkNode()) {
206            documents.add(composer.getNode());
207        }
208        return documents;
209    }
210
211    class CanonicalLoader extends Yaml {
212        public CanonicalLoader() {
213            super(new MyConstructor());
214        }
215
216        @Override
217        public Iterable<Object> loadAll(Reader yaml) {
218            StreamReader reader = new StreamReader(yaml);
219            StringBuilder buffer = new StringBuilder();
220            while (reader.peek() != '\0') {
221                buffer.append(reader.peek());
222                reader.forward();
223            }
224            CanonicalParser parser = new CanonicalParser(buffer.toString());
225            Composer composer = new Composer(parser, resolver);
226            this.constructor.setComposer(composer);
227            Iterator<Object> result = new Iterator<Object>() {
228                public boolean hasNext() {
229                    return constructor.checkData();
230                }
231
232                public Object next() {
233                    return constructor.getData();
234                }
235
236                public void remove() {
237                    throw new UnsupportedOperationException();
238                }
239            };
240            return new YamlIterable(result);
241        }
242
243        private class YamlIterable implements Iterable<Object> {
244            private Iterator<Object> iterator;
245
246            public YamlIterable(Iterator<Object> iterator) {
247                this.iterator = iterator;
248            }
249
250            public Iterator<Object> iterator() {
251                return iterator;
252            }
253
254        }
255
256    }
257
258    private class MyConstructor extends Constructor {
259        public MyConstructor() {
260            this.yamlConstructors.put(null, new ConstructUndefined());
261        }
262
263        private class ConstructUndefined extends AbstractConstruct {
264            public Object construct(Node node) {
265                return constructScalar((ScalarNode) node);
266            }
267        }
268    }
269
270    public void testConstructor() {
271        File[] files = getStreamsByExtension(".data", true);
272        assertTrue("No test files found.", files.length > 0);
273        Yaml myYaml = new Yaml(new MyConstructor());
274        Yaml canonicalYaml = new CanonicalLoader();
275        for (File file : files) {
276            try {
277                InputStream input = new FileInputStream(file);
278                Iterable<Object> documents1 = myYaml.loadAll(input);
279                int index = file.getAbsolutePath().lastIndexOf('.');
280                String canonicalName = file.getAbsolutePath().substring(0, index) + ".canonical";
281                File canonical = new File(canonicalName);
282                InputStream input2 = new FileInputStream(canonical);
283                Iterable<Object> documents2 = canonicalYaml.loadAll(input2);
284                input2.close();
285                Iterator<Object> iter2 = documents2.iterator();
286                for (Object object1 : documents1) {
287                    Object object2 = iter2.next();
288                    if (object2 != null) {
289                        assertFalse(System.identityHashCode(object1) == System
290                                .identityHashCode(object2));
291                    }
292                    assertEquals("" + object1, object1, object2);
293                }
294                input.close();
295            } catch (Exception e) {
296                System.out.println("Failed File: " + file);
297                // fail("Failed File: " + file + "; " + e.getMessage());
298                throw new RuntimeException(e);
299            }
300        }
301    }
302}
303