aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsomov <none@none>2009-03-14 13:25:40 +0100
committersomov <none@none>2009-03-14 13:25:40 +0100
commit159b07eeff6fdb7f32702b6243e827109455aecc (patch)
tree30fc25c989dd9ccc37ddad111241aad848460d3e
downloadsnakeyaml-159b07eeff6fdb7f32702b6243e827109455aecc.tar.gz
update wiki for JavaBeanParser
-rw-r--r--.classpath10
-rw-r--r--.hgignore5
-rw-r--r--.hgtags0
-rw-r--r--.project13
-rw-r--r--AUTHORS21
-rw-r--r--Eclipse-format.xml264
-rw-r--r--LICENSE19
-rw-r--r--README233
-rw-r--r--announcement.msg58
-rw-r--r--doc/wiki/Documentation.txt1335
-rw-r--r--pom.xml163
-rw-r--r--src/changes/changes.xml458
-rw-r--r--src/main/java/org/yaml/snakeyaml/Dumper.java56
-rw-r--r--src/main/java/org/yaml/snakeyaml/DumperOptions.java251
-rw-r--r--src/main/java/org/yaml/snakeyaml/JavaBeanParser.java75
-rw-r--r--src/main/java/org/yaml/snakeyaml/Loader.java86
-rw-r--r--src/main/java/org/yaml/snakeyaml/TypeDescription.java145
-rw-r--r--src/main/java/org/yaml/snakeyaml/Yaml.java223
-rw-r--r--src/main/java/org/yaml/snakeyaml/composer/Composer.java181
-rw-r--r--src/main/java/org/yaml/snakeyaml/composer/ComposerException.java19
-rw-r--r--src/main/java/org/yaml/snakeyaml/constructor/BaseConstructor.java152
-rw-r--r--src/main/java/org/yaml/snakeyaml/constructor/Construct.java10
-rw-r--r--src/main/java/org/yaml/snakeyaml/constructor/Constructor.java348
-rw-r--r--src/main/java/org/yaml/snakeyaml/constructor/ConstructorException.java19
-rw-r--r--src/main/java/org/yaml/snakeyaml/constructor/SafeConstructor.java402
-rw-r--r--src/main/java/org/yaml/snakeyaml/emitter/Emitter.java1422
-rw-r--r--src/main/java/org/yaml/snakeyaml/emitter/EmitterException.java17
-rwxr-xr-xsrc/main/java/org/yaml/snakeyaml/emitter/EmitterState.java15
-rw-r--r--src/main/java/org/yaml/snakeyaml/emitter/ScalarAnalysis.java31
-rw-r--r--src/main/java/org/yaml/snakeyaml/error/Mark.java107
-rw-r--r--src/main/java/org/yaml/snakeyaml/error/MarkedYAMLException.java61
-rw-r--r--src/main/java/org/yaml/snakeyaml/error/YAMLException.java19
-rw-r--r--src/main/java/org/yaml/snakeyaml/events/AliasEvent.java15
-rw-r--r--src/main/java/org/yaml/snakeyaml/events/CollectionEndEvent.java16
-rw-r--r--src/main/java/org/yaml/snakeyaml/events/CollectionStartEvent.java40
-rw-r--r--src/main/java/org/yaml/snakeyaml/events/DocumentEndEvent.java22
-rw-r--r--src/main/java/org/yaml/snakeyaml/events/DocumentStartEvent.java37
-rw-r--r--src/main/java/org/yaml/snakeyaml/events/Event.java51
-rw-r--r--src/main/java/org/yaml/snakeyaml/events/MappingEndEvent.java16
-rw-r--r--src/main/java/org/yaml/snakeyaml/events/MappingStartEvent.java16
-rw-r--r--src/main/java/org/yaml/snakeyaml/events/NodeEvent.java28
-rw-r--r--src/main/java/org/yaml/snakeyaml/events/ScalarEvent.java48
-rw-r--r--src/main/java/org/yaml/snakeyaml/events/SequenceEndEvent.java16
-rw-r--r--src/main/java/org/yaml/snakeyaml/events/SequenceStartEvent.java16
-rw-r--r--src/main/java/org/yaml/snakeyaml/events/StreamEndEvent.java15
-rw-r--r--src/main/java/org/yaml/snakeyaml/events/StreamStartEvent.java16
-rw-r--r--src/main/java/org/yaml/snakeyaml/introspector/FieldProperty.java32
-rw-r--r--src/main/java/org/yaml/snakeyaml/introspector/MethodProperty.java32
-rw-r--r--src/main/java/org/yaml/snakeyaml/introspector/Property.java35
-rw-r--r--src/main/java/org/yaml/snakeyaml/nodes/CollectionNode.java30
-rw-r--r--src/main/java/org/yaml/snakeyaml/nodes/MappingNode.java71
-rw-r--r--src/main/java/org/yaml/snakeyaml/nodes/Node.java76
-rw-r--r--src/main/java/org/yaml/snakeyaml/nodes/NodeId.java8
-rw-r--r--src/main/java/org/yaml/snakeyaml/nodes/ScalarNode.java27
-rw-r--r--src/main/java/org/yaml/snakeyaml/nodes/SequenceNode.java43
-rw-r--r--src/main/java/org/yaml/snakeyaml/parser/Parser.java22
-rw-r--r--src/main/java/org/yaml/snakeyaml/parser/ParserException.java18
-rw-r--r--src/main/java/org/yaml/snakeyaml/parser/ParserImpl.java855
-rw-r--r--src/main/java/org/yaml/snakeyaml/parser/Production.java10
-rw-r--r--src/main/java/org/yaml/snakeyaml/reader/Reader.java175
-rw-r--r--src/main/java/org/yaml/snakeyaml/reader/ReaderException.java26
-rw-r--r--src/main/java/org/yaml/snakeyaml/reader/UnicodeReader.java105
-rw-r--r--src/main/java/org/yaml/snakeyaml/representer/BaseRepresenter.java161
-rw-r--r--src/main/java/org/yaml/snakeyaml/representer/Represent.java10
-rw-r--r--src/main/java/org/yaml/snakeyaml/representer/Representer.java143
-rw-r--r--src/main/java/org/yaml/snakeyaml/representer/SafeRepresenter.java219
-rw-r--r--src/main/java/org/yaml/snakeyaml/resolver/RagelMachine.rl81
-rw-r--r--src/main/java/org/yaml/snakeyaml/resolver/Resolver.java114
-rw-r--r--src/main/java/org/yaml/snakeyaml/resolver/ResolverTuple.java29
-rw-r--r--src/main/java/org/yaml/snakeyaml/scanner/Scanner.java36
-rw-r--r--src/main/java/org/yaml/snakeyaml/scanner/ScannerException.java25
-rw-r--r--src/main/java/org/yaml/snakeyaml/scanner/ScannerImpl.java1757
-rw-r--r--src/main/java/org/yaml/snakeyaml/scanner/SimpleKey.java59
-rw-r--r--src/main/java/org/yaml/snakeyaml/serializer/Serializer.java191
-rw-r--r--src/main/java/org/yaml/snakeyaml/serializer/SerializerException.java17
-rw-r--r--src/main/java/org/yaml/snakeyaml/tokens/AliasToken.java32
-rw-r--r--src/main/java/org/yaml/snakeyaml/tokens/AnchorToken.java32
-rw-r--r--src/main/java/org/yaml/snakeyaml/tokens/BlockEndToken.java21
-rw-r--r--src/main/java/org/yaml/snakeyaml/tokens/BlockEntryToken.java21
-rw-r--r--src/main/java/org/yaml/snakeyaml/tokens/BlockMappingStartToken.java21
-rw-r--r--src/main/java/org/yaml/snakeyaml/tokens/BlockSequenceStartToken.java21
-rw-r--r--src/main/java/org/yaml/snakeyaml/tokens/DirectiveToken.java49
-rw-r--r--src/main/java/org/yaml/snakeyaml/tokens/DocumentEndToken.java21
-rw-r--r--src/main/java/org/yaml/snakeyaml/tokens/DocumentStartToken.java21
-rw-r--r--src/main/java/org/yaml/snakeyaml/tokens/FlowEntryToken.java21
-rw-r--r--src/main/java/org/yaml/snakeyaml/tokens/FlowMappingEndToken.java21
-rw-r--r--src/main/java/org/yaml/snakeyaml/tokens/FlowMappingStartToken.java21
-rw-r--r--src/main/java/org/yaml/snakeyaml/tokens/FlowSequenceEndToken.java21
-rw-r--r--src/main/java/org/yaml/snakeyaml/tokens/FlowSequenceStartToken.java21
-rw-r--r--src/main/java/org/yaml/snakeyaml/tokens/KeyToken.java21
-rw-r--r--src/main/java/org/yaml/snakeyaml/tokens/ScalarToken.java48
-rw-r--r--src/main/java/org/yaml/snakeyaml/tokens/StreamEndToken.java21
-rw-r--r--src/main/java/org/yaml/snakeyaml/tokens/StreamStartToken.java21
-rw-r--r--src/main/java/org/yaml/snakeyaml/tokens/TagToken.java37
-rw-r--r--src/main/java/org/yaml/snakeyaml/tokens/Token.java59
-rw-r--r--src/main/java/org/yaml/snakeyaml/tokens/ValueToken.java21
-rw-r--r--src/main/java/org/yaml/snakeyaml/util/Base64Coder.java109
-rw-r--r--src/test/java/examples/AnyObjectExampleTest.java50
-rw-r--r--src/test/java/examples/CollectionStyleTest.java28
-rw-r--r--src/test/java/examples/CustomConstructor.java22
-rw-r--r--src/test/java/examples/CustomListExampleTest.java31
-rw-r--r--src/test/java/examples/CustomMapExampleTest.java36
-rw-r--r--src/test/java/examples/Dice.java41
-rw-r--r--src/test/java/examples/DiceExampleTest.java97
-rw-r--r--src/test/java/examples/DumpExampleTest.java128
-rw-r--r--src/test/java/examples/Hero.java30
-rw-r--r--src/test/java/examples/LoadExampleTest.java59
-rw-r--r--src/test/java/examples/SafeConstructorExampleTest.java42
-rw-r--r--src/test/java/examples/SpringTest.java21
-rw-r--r--src/test/java/org/pyyaml/AnInstance.java34
-rw-r--r--src/test/java/org/pyyaml/CanonicalException.java19
-rw-r--r--src/test/java/org/pyyaml/CanonicalLoader.java72
-rw-r--r--src/test/java/org/pyyaml/CanonicalParser.java198
-rw-r--r--src/test/java/org/pyyaml/CanonicalScanner.java301
-rw-r--r--src/test/java/org/pyyaml/PyCanonicalTest.java53
-rw-r--r--src/test/java/org/pyyaml/PyEmitterTest.java284
-rw-r--r--src/test/java/org/pyyaml/PyErrorsTest.java120
-rw-r--r--src/test/java/org/pyyaml/PyImportTest.java128
-rw-r--r--src/test/java/org/pyyaml/PyMarkTest.java45
-rw-r--r--src/test/java/org/pyyaml/PyReaderTest.java36
-rw-r--r--src/test/java/org/pyyaml/PyRecursiveTest.java63
-rw-r--r--src/test/java/org/pyyaml/PyStructureTest.java287
-rw-r--r--src/test/java/org/pyyaml/PyTokensTest.java140
-rw-r--r--src/test/java/org/yaml/snakeyaml/Address.java11
-rw-r--r--src/test/java/org/yaml/snakeyaml/BinaryBean.java26
-rw-r--r--src/test/java/org/yaml/snakeyaml/BinaryJavaBeanTest.java20
-rw-r--r--src/test/java/org/yaml/snakeyaml/Chapter2_1Test.java96
-rw-r--r--src/test/java/org/yaml/snakeyaml/Chapter2_2Test.java101
-rw-r--r--src/test/java/org/yaml/snakeyaml/Chapter2_3Test.java120
-rw-r--r--src/test/java/org/yaml/snakeyaml/Chapter2_4Test.java171
-rw-r--r--src/test/java/org/yaml/snakeyaml/Chapter2_5Test.java52
-rw-r--r--src/test/java/org/yaml/snakeyaml/DumperOptionsTest.java261
-rw-r--r--src/test/java/org/yaml/snakeyaml/DumperTest.java82
-rw-r--r--src/test/java/org/yaml/snakeyaml/EnumBean.java36
-rw-r--r--src/test/java/org/yaml/snakeyaml/EnumTest.java175
-rw-r--r--src/test/java/org/yaml/snakeyaml/Example2_24Test.java234
-rw-r--r--src/test/java/org/yaml/snakeyaml/Example2_27Test.java35
-rw-r--r--src/test/java/org/yaml/snakeyaml/Invoice.java18
-rw-r--r--src/test/java/org/yaml/snakeyaml/JavaBeanParserTest.java95
-rw-r--r--src/test/java/org/yaml/snakeyaml/ParallelTest.java83
-rw-r--r--src/test/java/org/yaml/snakeyaml/Person.java10
-rw-r--r--src/test/java/org/yaml/snakeyaml/Product.java11
-rw-r--r--src/test/java/org/yaml/snakeyaml/StressTest.java60
-rw-r--r--src/test/java/org/yaml/snakeyaml/Suit.java8
-rw-r--r--src/test/java/org/yaml/snakeyaml/TypeDescriptionTest.java21
-rw-r--r--src/test/java/org/yaml/snakeyaml/Util.java39
-rw-r--r--src/test/java/org/yaml/snakeyaml/YamlDocument.java71
-rw-r--r--src/test/java/org/yaml/snakeyaml/YamlStream.java83
-rw-r--r--src/test/java/org/yaml/snakeyaml/YamlTest.java18
-rw-r--r--src/test/java/org/yaml/snakeyaml/composer/ComposerImplTest.java37
-rw-r--r--src/test/java/org/yaml/snakeyaml/constructor/ArrayTagsTest.java89
-rw-r--r--src/test/java/org/yaml/snakeyaml/constructor/BeanConstructorTest.java228
-rw-r--r--src/test/java/org/yaml/snakeyaml/constructor/Car.java27
-rw-r--r--src/test/java/org/yaml/snakeyaml/constructor/Child1.java16
-rw-r--r--src/test/java/org/yaml/snakeyaml/constructor/ClassTagsTest.java101
-rw-r--r--src/test/java/org/yaml/snakeyaml/constructor/ConstructorMappingTest.java55
-rw-r--r--src/test/java/org/yaml/snakeyaml/constructor/ConstructorSequenceTest.java74
-rw-r--r--src/test/java/org/yaml/snakeyaml/constructor/ConstructorTest.java89
-rw-r--r--src/test/java/org/yaml/snakeyaml/constructor/ImplicitTagsTest.java149
-rw-r--r--src/test/java/org/yaml/snakeyaml/constructor/MyCar.java37
-rw-r--r--src/test/java/org/yaml/snakeyaml/constructor/MyWheel.java49
-rw-r--r--src/test/java/org/yaml/snakeyaml/constructor/Parent1.java26
-rw-r--r--src/test/java/org/yaml/snakeyaml/constructor/Person.java51
-rw-r--r--src/test/java/org/yaml/snakeyaml/constructor/SafeConstructorTest.java39
-rw-r--r--src/test/java/org/yaml/snakeyaml/constructor/TestBean.java71
-rw-r--r--src/test/java/org/yaml/snakeyaml/constructor/TestBean1.java192
-rw-r--r--src/test/java/org/yaml/snakeyaml/constructor/TypeSafeCollectionsTest.java82
-rw-r--r--src/test/java/org/yaml/snakeyaml/constructor/Wheel.java44
-rw-r--r--src/test/java/org/yaml/snakeyaml/emitter/EmitterTest.java82
-rw-r--r--src/test/java/org/yaml/snakeyaml/emitter/EventConstructor.java106
-rw-r--r--src/test/java/org/yaml/snakeyaml/emitter/EventsLoader.java13
-rw-r--r--src/test/java/org/yaml/snakeyaml/error/MarkTest.java25
-rw-r--r--src/test/java/org/yaml/snakeyaml/error/MarkedYAMLExceptionTest.java27
-rw-r--r--src/test/java/org/yaml/snakeyaml/events/ScalarEventTest.java27
-rw-r--r--src/test/java/org/yaml/snakeyaml/introspector/MethodPropertyTest.java22
-rw-r--r--src/test/java/org/yaml/snakeyaml/nodes/NodeTest.java28
-rw-r--r--src/test/java/org/yaml/snakeyaml/nodes/ScalarNodeTest.java26
-rw-r--r--src/test/java/org/yaml/snakeyaml/nodes/SequenceNodeTest.java16
-rw-r--r--src/test/java/org/yaml/snakeyaml/parser/ParserImplTest.java88
-rw-r--r--src/test/java/org/yaml/snakeyaml/reader/IoReaderTest.java25
-rw-r--r--src/test/java/org/yaml/snakeyaml/reader/ReaderBomTest.java101
-rw-r--r--src/test/java/org/yaml/snakeyaml/reader/ReaderStringTest.java61
-rw-r--r--src/test/java/org/yaml/snakeyaml/representer/RepresentTest.java83
-rw-r--r--src/test/java/org/yaml/snakeyaml/representer/RepresenterTest.java131
-rw-r--r--src/test/java/org/yaml/snakeyaml/representer/SafeRepresenterTest.java105
-rw-r--r--src/test/java/org/yaml/snakeyaml/resolver/RagelMachine.java317
-rw-r--r--src/test/java/org/yaml/snakeyaml/resolver/RagelMachineTest.java104
-rw-r--r--src/test/java/org/yaml/snakeyaml/resolver/ResolverTest.java141
-rw-r--r--src/test/java/org/yaml/snakeyaml/resolver/ResolverTupleTest.java16
-rw-r--r--src/test/java/org/yaml/snakeyaml/scanner/ScannerImplTest.java47
-rw-r--r--src/test/java/org/yaml/snakeyaml/scanner/SimpleKeyTest.java14
-rw-r--r--src/test/java/org/yaml/snakeyaml/serializer/SerializerTest.java89
-rw-r--r--src/test/java/org/yaml/snakeyaml/tokens/AliasTokenTest.java29
-rw-r--r--src/test/java/org/yaml/snakeyaml/tokens/AnchorTokenTest.java23
-rw-r--r--src/test/java/org/yaml/snakeyaml/tokens/BlockEndTokenTest.java23
-rw-r--r--src/test/java/org/yaml/snakeyaml/tokens/BlockEntryTokenTest.java18
-rw-r--r--src/test/java/org/yaml/snakeyaml/tokens/BlockSequenceStartTokenTest.java17
-rw-r--r--src/test/java/org/yaml/snakeyaml/tokens/DirectiveTokenTest.java56
-rw-r--r--src/test/java/org/yaml/snakeyaml/tokens/DocumentEndTokenTest.java17
-rw-r--r--src/test/java/org/yaml/snakeyaml/tokens/DocumentStartTokenTest.java17
-rw-r--r--src/test/java/org/yaml/snakeyaml/tokens/FlowEntryTokenTest.java17
-rw-r--r--src/test/java/org/yaml/snakeyaml/tokens/FlowMappingStartTokenTest.java17
-rw-r--r--src/test/java/org/yaml/snakeyaml/tokens/FlowSequenceStartTokenTest.java17
-rw-r--r--src/test/java/org/yaml/snakeyaml/tokens/StreamStartTokenTest.java17
-rw-r--r--src/test/java/org/yaml/snakeyaml/tokens/TagTokenTest.java33
-rw-r--r--src/test/java/org/yaml/snakeyaml/types/AbstractTest.java36
-rw-r--r--src/test/java/org/yaml/snakeyaml/types/BinaryTagTest.java64
-rw-r--r--src/test/java/org/yaml/snakeyaml/types/BoolTagTest.java59
-rw-r--r--src/test/java/org/yaml/snakeyaml/types/FloatTagTest.java55
-rw-r--r--src/test/java/org/yaml/snakeyaml/types/IntTagTest.java55
-rw-r--r--src/test/java/org/yaml/snakeyaml/types/MapTagTest.java59
-rw-r--r--src/test/java/org/yaml/snakeyaml/types/MergeTagTest.java59
-rw-r--r--src/test/java/org/yaml/snakeyaml/types/NullTagTest.java73
-rw-r--r--src/test/java/org/yaml/snakeyaml/types/OmapTagTest.java35
-rw-r--r--src/test/java/org/yaml/snakeyaml/types/PairsTagTest.java59
-rw-r--r--src/test/java/org/yaml/snakeyaml/types/SeqTagTest.java70
-rw-r--r--src/test/java/org/yaml/snakeyaml/types/SetTagTest.java33
-rw-r--r--src/test/java/org/yaml/snakeyaml/types/StrTagTest.java130
-rw-r--r--src/test/java/org/yaml/snakeyaml/types/TimestampTagTest.java93
-rw-r--r--src/test/java/org/yaml/snakeyaml/types/ValueTagTest.java49
-rw-r--r--src/test/resources/constructor/car-no-root-class-map.yaml15
-rw-r--r--src/test/resources/constructor/car-no-root-class.yaml8
-rw-r--r--src/test/resources/constructor/car-with-tags.yaml8
-rw-r--r--src/test/resources/constructor/car-without-root-tag.yaml5
-rw-r--r--src/test/resources/constructor/car-without-tags.yaml8
-rw-r--r--src/test/resources/constructor/cararray-with-tags.yaml8
-rw-r--r--src/test/resources/constructor/carwheel-root-map.yaml3
-rw-r--r--src/test/resources/constructor/carwheel-without-tags.yaml6
-rw-r--r--src/test/resources/constructor/test-primitives1.yaml23
-rw-r--r--src/test/resources/examples/any-object-example.yaml6
-rw-r--r--src/test/resources/examples/spring.xml39
-rw-r--r--src/test/resources/pyyaml/a-nasty-libyaml-bug.loader-error1
-rw-r--r--src/test/resources/pyyaml/aliases.events8
-rw-r--r--src/test/resources/pyyaml/bool.data4
-rw-r--r--src/test/resources/pyyaml/colon-in-flow-context.loader-error1
-rw-r--r--src/test/resources/pyyaml/construct-binary.data12
-rw-r--r--src/test/resources/pyyaml/construct-bool.data9
-rw-r--r--src/test/resources/pyyaml/construct-custom.data26
-rw-r--r--src/test/resources/pyyaml/construct-float.data6
-rw-r--r--src/test/resources/pyyaml/construct-int.data6
-rw-r--r--src/test/resources/pyyaml/construct-map.data6
-rw-r--r--src/test/resources/pyyaml/construct-merge.data27
-rw-r--r--src/test/resources/pyyaml/construct-null.data18
-rw-r--r--src/test/resources/pyyaml/construct-omap.data8
-rw-r--r--src/test/resources/pyyaml/construct-pairs.data7
-rw-r--r--src/test/resources/pyyaml/construct-seq.data15
-rw-r--r--src/test/resources/pyyaml/construct-set.data7
-rw-r--r--src/test/resources/pyyaml/construct-str-ascii.data1
-rw-r--r--src/test/resources/pyyaml/construct-str-utf8.data1
-rw-r--r--src/test/resources/pyyaml/construct-str.data1
-rw-r--r--src/test/resources/pyyaml/construct-timestamp.data5
-rw-r--r--src/test/resources/pyyaml/construct-value.data10
-rw-r--r--src/test/resources/pyyaml/document-separator-in-quoted-scalar.loader-error11
-rw-r--r--src/test/resources/pyyaml/documents.events11
-rw-r--r--src/test/resources/pyyaml/duplicate-anchor-1.loader-error3
-rw-r--r--src/test/resources/pyyaml/duplicate-anchor-2.loader-error1
-rw-r--r--src/test/resources/pyyaml/duplicate-key.former-loader-error.data3
-rw-r--r--src/test/resources/pyyaml/duplicate-mapping-key.former-loader-error.data6
-rw-r--r--src/test/resources/pyyaml/duplicate-merge-key.former-loader-error.data4
-rw-r--r--src/test/resources/pyyaml/duplicate-tag-directive.loader-error3
-rw-r--r--src/test/resources/pyyaml/duplicate-value-key.former-loader-error.data4
-rw-r--r--src/test/resources/pyyaml/duplicate-yaml-directive.loader-error3
-rw-r--r--src/test/resources/pyyaml/emit-block-scalar-in-simple-key-context-bug.canonical6
-rw-r--r--src/test/resources/pyyaml/emit-block-scalar-in-simple-key-context-bug.data4
-rw-r--r--src/test/resources/pyyaml/emitting-unacceptable-unicode-character-bug.data1
-rw-r--r--src/test/resources/pyyaml/empty-anchor.emitter-error5
-rw-r--r--src/test/resources/pyyaml/empty-document-bug.canonical1
-rw-r--r--src/test/resources/pyyaml/empty-document-bug.data0
-rw-r--r--src/test/resources/pyyaml/empty-documents.single-loader-error2
-rw-r--r--src/test/resources/pyyaml/empty-tag-handle.emitter-error5
-rw-r--r--src/test/resources/pyyaml/empty-tag-prefix.emitter-error5
-rw-r--r--src/test/resources/pyyaml/empty-tag.emitter-error5
-rw-r--r--src/test/resources/pyyaml/expected-document-end.emitter-error6
-rw-r--r--src/test/resources/pyyaml/expected-document-start.emitter-error4
-rw-r--r--src/test/resources/pyyaml/expected-mapping.loader-error1
-rw-r--r--src/test/resources/pyyaml/expected-node-1.emitter-error4
-rw-r--r--src/test/resources/pyyaml/expected-node-2.emitter-error7
-rw-r--r--src/test/resources/pyyaml/expected-nothing.emitter-error4
-rw-r--r--src/test/resources/pyyaml/expected-scalar.loader-error1
-rw-r--r--src/test/resources/pyyaml/expected-sequence.loader-error1
-rw-r--r--src/test/resources/pyyaml/expected-stream-start.emitter-error2
-rw-r--r--src/test/resources/pyyaml/explicit-document.single-loader-error4
-rw-r--r--src/test/resources/pyyaml/fetch-complex-value-bug.loader-error2
-rw-r--r--src/test/resources/pyyaml/float-representer-2.3-bug.data5
-rw-r--r--src/test/resources/pyyaml/float.data6
-rw-r--r--src/test/resources/pyyaml/forbidden-entry.loader-error2
-rw-r--r--src/test/resources/pyyaml/forbidden-key.loader-error2
-rw-r--r--src/test/resources/pyyaml/forbidden-value.loader-error1
-rw-r--r--src/test/resources/pyyaml/implicit-document.single-loader-error3
-rw-r--r--src/test/resources/pyyaml/int.data6
-rw-r--r--src/test/resources/pyyaml/invalid-anchor-1.loader-error1
-rw-r--r--src/test/resources/pyyaml/invalid-anchor-2.loader-error8
-rw-r--r--src/test/resources/pyyaml/invalid-anchor.emitter-error5
-rw-r--r--src/test/resources/pyyaml/invalid-base64-data.loader-error2
-rw-r--r--src/test/resources/pyyaml/invalid-block-scalar-indicator.loader-error2
-rw-r--r--src/test/resources/pyyaml/invalid-character.loader-errorbin0 -> 2209 bytes
-rw-r--r--src/test/resources/pyyaml/invalid-character.stream-errorbin0 -> 2209 bytes
-rw-r--r--src/test/resources/pyyaml/invalid-directive-line.loader-error2
-rw-r--r--src/test/resources/pyyaml/invalid-directive-name-1.loader-error2
-rw-r--r--src/test/resources/pyyaml/invalid-directive-name-2.loader-error2
-rw-r--r--src/test/resources/pyyaml/invalid-escape-character.loader-error1
-rw-r--r--src/test/resources/pyyaml/invalid-escape-numbers.loader-error1
-rw-r--r--src/test/resources/pyyaml/invalid-indentation-indicator-1.loader-error2
-rw-r--r--src/test/resources/pyyaml/invalid-indentation-indicator-2.loader-error2
-rw-r--r--src/test/resources/pyyaml/invalid-merge-1.loader-error2
-rw-r--r--src/test/resources/pyyaml/invalid-merge-2.loader-error2
-rw-r--r--src/test/resources/pyyaml/invalid-omap-1.loader-error3
-rw-r--r--src/test/resources/pyyaml/invalid-omap-2.loader-error3
-rw-r--r--src/test/resources/pyyaml/invalid-omap-3.loader-error4
-rw-r--r--src/test/resources/pyyaml/invalid-pairs-1.loader-error3
-rw-r--r--src/test/resources/pyyaml/invalid-pairs-2.loader-error3
-rw-r--r--src/test/resources/pyyaml/invalid-pairs-3.loader-error4
-rw-r--r--src/test/resources/pyyaml/invalid-simple-key.loader-error3
-rw-r--r--src/test/resources/pyyaml/invalid-single-quote-bug.data2
-rw-r--r--src/test/resources/pyyaml/invalid-starting-character.loader-error1
-rw-r--r--src/test/resources/pyyaml/invalid-tag-1.loader-error1
-rw-r--r--src/test/resources/pyyaml/invalid-tag-2.loader-error1
-rw-r--r--src/test/resources/pyyaml/invalid-tag-directive-handle.loader-error2
-rw-r--r--src/test/resources/pyyaml/invalid-tag-directive-prefix.loader-error2
-rw-r--r--src/test/resources/pyyaml/invalid-tag-handle-1.emitter-error5
-rw-r--r--src/test/resources/pyyaml/invalid-tag-handle-1.loader-error2
-rw-r--r--src/test/resources/pyyaml/invalid-tag-handle-2.emitter-error5
-rw-r--r--src/test/resources/pyyaml/invalid-tag-handle-2.loader-error2
-rw-r--r--src/test/resources/pyyaml/invalid-uri-escapes-1.loader-error1
-rw-r--r--src/test/resources/pyyaml/invalid-uri-escapes-2.loader-error1
-rw-r--r--src/test/resources/pyyaml/invalid-uri-escapes-3.loader-error1
-rw-r--r--src/test/resources/pyyaml/invalid-uri.loader-error1
-rw-r--r--src/test/resources/pyyaml/invalid-utf8-byte.loader-error18
-rw-r--r--src/test/resources/pyyaml/invalid-utf8-byte.stream-error18
-rw-r--r--src/test/resources/pyyaml/invalid-yaml-directive-version-1.loader-error3
-rw-r--r--src/test/resources/pyyaml/invalid-yaml-directive-version-2.loader-error2
-rw-r--r--src/test/resources/pyyaml/invalid-yaml-directive-version-3.loader-error2
-rw-r--r--src/test/resources/pyyaml/invalid-yaml-directive-version-4.loader-error2
-rw-r--r--src/test/resources/pyyaml/invalid-yaml-directive-version-5.loader-error2
-rw-r--r--src/test/resources/pyyaml/invalid-yaml-directive-version-6.loader-error2
-rw-r--r--src/test/resources/pyyaml/invalid-yaml-version.loader-error2
-rw-r--r--src/test/resources/pyyaml/mappings.events44
-rw-r--r--src/test/resources/pyyaml/merge.data1
-rw-r--r--src/test/resources/pyyaml/more-floats.data1
-rw-r--r--src/test/resources/pyyaml/negative-float-bug.data1
-rw-r--r--src/test/resources/pyyaml/no-alias-anchor.emitter-error8
-rw-r--r--src/test/resources/pyyaml/no-block-collection-end.loader-error3
-rw-r--r--src/test/resources/pyyaml/no-block-mapping-end-2.loader-error3
-rw-r--r--src/test/resources/pyyaml/no-block-mapping-end.loader-error1
-rw-r--r--src/test/resources/pyyaml/no-document-start.loader-error3
-rw-r--r--src/test/resources/pyyaml/no-flow-mapping-end.loader-error1
-rw-r--r--src/test/resources/pyyaml/no-flow-sequence-end.loader-error1
-rw-r--r--src/test/resources/pyyaml/no-node-1.loader-error1
-rw-r--r--src/test/resources/pyyaml/no-node-2.loader-error1
-rw-r--r--src/test/resources/pyyaml/no-tag.emitter-error5
-rw-r--r--src/test/resources/pyyaml/null.data3
-rw-r--r--src/test/resources/pyyaml/odd-utf16.stream-errorbin0 -> 2463 bytes
-rw-r--r--src/test/resources/pyyaml/remove-possible-simple-key-bug.loader-error3
-rw-r--r--src/test/resources/pyyaml/resolver.data30
-rw-r--r--src/test/resources/pyyaml/run-parser-crash-bug.data8
-rw-r--r--src/test/resources/pyyaml/scalars.events28
-rw-r--r--src/test/resources/pyyaml/scan-document-end-bug.canonical3
-rw-r--r--src/test/resources/pyyaml/scan-document-end-bug.data3
-rw-r--r--src/test/resources/pyyaml/scan-line-break-bug.canonical3
-rw-r--r--src/test/resources/pyyaml/scan-line-break-bug.data3
-rw-r--r--src/test/resources/pyyaml/sequences.events81
-rw-r--r--src/test/resources/pyyaml/single-dot-is-not-float-bug.data1
-rw-r--r--src/test/resources/pyyaml/sloppy-indentation.canonical18
-rw-r--r--src/test/resources/pyyaml/sloppy-indentation.data17
-rw-r--r--src/test/resources/pyyaml/spec-02-01.data3
-rw-r--r--src/test/resources/pyyaml/spec-02-01.tokens1
-rw-r--r--src/test/resources/pyyaml/spec-02-02.data3
-rw-r--r--src/test/resources/pyyaml/spec-02-02.tokens5
-rw-r--r--src/test/resources/pyyaml/spec-02-03.data8
-rw-r--r--src/test/resources/pyyaml/spec-02-03.tokens4
-rw-r--r--src/test/resources/pyyaml/spec-02-04.data8
-rw-r--r--src/test/resources/pyyaml/spec-02-04.tokens4
-rw-r--r--src/test/resources/pyyaml/spec-02-05.data3
-rw-r--r--src/test/resources/pyyaml/spec-02-05.tokens5
-rw-r--r--src/test/resources/pyyaml/spec-02-06.data5
-rw-r--r--src/test/resources/pyyaml/spec-02-06.tokens4
-rw-r--r--src/test/resources/pyyaml/spec-02-07.data10
-rw-r--r--src/test/resources/pyyaml/spec-02-07.tokens12
-rw-r--r--src/test/resources/pyyaml/spec-02-08.data10
-rw-r--r--src/test/resources/pyyaml/spec-02-08.tokens15
-rw-r--r--src/test/resources/pyyaml/spec-02-09.data8
-rw-r--r--src/test/resources/pyyaml/spec-02-09.tokens5
-rw-r--r--src/test/resources/pyyaml/spec-02-10.data8
-rw-r--r--src/test/resources/pyyaml/spec-02-10.tokens5
-rw-r--r--src/test/resources/pyyaml/spec-02-11.data9
-rw-r--r--src/test/resources/pyyaml/spec-02-11.tokens6
-rw-r--r--src/test/resources/pyyaml/spec-02-12.data8
-rw-r--r--src/test/resources/pyyaml/spec-02-12.tokens6
-rw-r--r--src/test/resources/pyyaml/spec-02-13.data4
-rw-r--r--src/test/resources/pyyaml/spec-02-13.tokens1
-rw-r--r--src/test/resources/pyyaml/spec-02-14.data4
-rw-r--r--src/test/resources/pyyaml/spec-02-14.tokens1
-rw-r--r--src/test/resources/pyyaml/spec-02-15.data8
-rw-r--r--src/test/resources/pyyaml/spec-02-15.tokens1
-rw-r--r--src/test/resources/pyyaml/spec-02-16.data7
-rw-r--r--src/test/resources/pyyaml/spec-02-16.tokens5
-rw-r--r--src/test/resources/pyyaml/spec-02-17.data7
-rw-r--r--src/test/resources/pyyaml/spec-02-17.tokens8
-rw-r--r--src/test/resources/pyyaml/spec-02-18.data6
-rw-r--r--src/test/resources/pyyaml/spec-02-18.tokens4
-rw-r--r--src/test/resources/pyyaml/spec-02-19.data5
-rw-r--r--src/test/resources/pyyaml/spec-02-19.tokens7
-rw-r--r--src/test/resources/pyyaml/spec-02-20.data6
-rw-r--r--src/test/resources/pyyaml/spec-02-20.tokens8
-rw-r--r--src/test/resources/pyyaml/spec-02-21.data4
-rw-r--r--src/test/resources/pyyaml/spec-02-21.tokens6
-rw-r--r--src/test/resources/pyyaml/spec-02-22.data4
-rw-r--r--src/test/resources/pyyaml/spec-02-22.tokens6
-rw-r--r--src/test/resources/pyyaml/spec-02-23.data13
-rw-r--r--src/test/resources/pyyaml/spec-02-23.tokens6
-rw-r--r--src/test/resources/pyyaml/spec-02-24.data14
-rw-r--r--src/test/resources/pyyaml/spec-02-24.tokens20
-rw-r--r--src/test/resources/pyyaml/spec-02-25.data7
-rw-r--r--src/test/resources/pyyaml/spec-02-25.tokens6
-rw-r--r--src/test/resources/pyyaml/spec-02-26.data7
-rw-r--r--src/test/resources/pyyaml/spec-02-26.tokens6
-rw-r--r--src/test/resources/pyyaml/spec-02-27.data29
-rw-r--r--src/test/resources/pyyaml/spec-02-27.tokens20
-rw-r--r--src/test/resources/pyyaml/spec-02-28.data26
-rw-r--r--src/test/resources/pyyaml/spec-02-28.tokens23
-rw-r--r--src/test/resources/pyyaml/spec-05-01-utf16be.databin0 -> 34 bytes
-rw-r--r--src/test/resources/pyyaml/spec-05-01-utf16le.databin0 -> 34 bytes
-rw-r--r--src/test/resources/pyyaml/spec-05-01-utf8.data1
-rw-r--r--src/test/resources/pyyaml/spec-05-02-utf16be.databin0 -> 90 bytes
-rw-r--r--src/test/resources/pyyaml/spec-05-02-utf16le.databin0 -> 90 bytes
-rw-r--r--src/test/resources/pyyaml/spec-05-02-utf8.data3
-rw-r--r--src/test/resources/pyyaml/spec-05-03.canonical14
-rw-r--r--src/test/resources/pyyaml/spec-05-03.data7
-rw-r--r--src/test/resources/pyyaml/spec-05-04.canonical13
-rw-r--r--src/test/resources/pyyaml/spec-05-04.data2
-rw-r--r--src/test/resources/pyyaml/spec-05-05.data1
-rw-r--r--src/test/resources/pyyaml/spec-05-06.canonical8
-rw-r--r--src/test/resources/pyyaml/spec-05-06.data2
-rw-r--r--src/test/resources/pyyaml/spec-05-07.canonical8
-rw-r--r--src/test/resources/pyyaml/spec-05-07.data4
-rw-r--r--src/test/resources/pyyaml/spec-05-08.canonical8
-rw-r--r--src/test/resources/pyyaml/spec-05-08.data2
-rw-r--r--src/test/resources/pyyaml/spec-05-09.canonical3
-rw-r--r--src/test/resources/pyyaml/spec-05-09.data2
-rw-r--r--src/test/resources/pyyaml/spec-05-10.data2
-rw-r--r--src/test/resources/pyyaml/spec-05-11.canonical6
-rw-r--r--src/test/resources/pyyaml/spec-05-11.data3
-rw-r--r--src/test/resources/pyyaml/spec-05-12.data9
-rw-r--r--src/test/resources/pyyaml/spec-05-13.canonical5
-rw-r--r--src/test/resources/pyyaml/spec-05-13.data3
-rw-r--r--src/test/resources/pyyaml/spec-05-14.canonical7
-rw-r--r--src/test/resources/pyyaml/spec-05-14.data2
-rw-r--r--src/test/resources/pyyaml/spec-05-15.data3
-rw-r--r--src/test/resources/pyyaml/spec-06-01.canonical15
-rw-r--r--src/test/resources/pyyaml/spec-06-01.data14
-rw-r--r--src/test/resources/pyyaml/spec-06-02.data3
-rw-r--r--src/test/resources/pyyaml/spec-06-03.canonical6
-rw-r--r--src/test/resources/pyyaml/spec-06-03.data2
-rw-r--r--src/test/resources/pyyaml/spec-06-04.canonical6
-rw-r--r--src/test/resources/pyyaml/spec-06-04.data4
-rw-r--r--src/test/resources/pyyaml/spec-06-05.canonical16
-rw-r--r--src/test/resources/pyyaml/spec-06-05.data6
-rw-r--r--src/test/resources/pyyaml/spec-06-06.canonical10
-rw-r--r--src/test/resources/pyyaml/spec-06-06.data7
-rw-r--r--src/test/resources/pyyaml/spec-06-07.canonical6
-rw-r--r--src/test/resources/pyyaml/spec-06-07.data8
-rw-r--r--src/test/resources/pyyaml/spec-06-08.canonical5
-rw-r--r--src/test/resources/pyyaml/spec-06-08.data2
-rw-r--r--src/test/resources/pyyaml/spec-07-01.canonical3
-rw-r--r--src/test/resources/pyyaml/spec-07-01.data3
-rw-r--r--src/test/resources/pyyaml/spec-07-02.canonical3
-rw-r--r--src/test/resources/pyyaml/spec-07-02.data4
-rw-r--r--src/test/resources/pyyaml/spec-07-03.data3
-rw-r--r--src/test/resources/pyyaml/spec-07-04.canonical3
-rw-r--r--src/test/resources/pyyaml/spec-07-04.data3
-rw-r--r--src/test/resources/pyyaml/spec-07-05.data3
-rw-r--r--src/test/resources/pyyaml/spec-07-06.canonical6
-rw-r--r--src/test/resources/pyyaml/spec-07-06.data5
-rw-r--r--src/test/resources/pyyaml/spec-07-07a.canonical3
-rw-r--r--src/test/resources/pyyaml/spec-07-07a.data2
-rw-r--r--src/test/resources/pyyaml/spec-07-07b.canonical3
-rw-r--r--src/test/resources/pyyaml/spec-07-07b.data4
-rw-r--r--src/test/resources/pyyaml/spec-07-08.canonical7
-rw-r--r--src/test/resources/pyyaml/spec-07-08.data9
-rw-r--r--src/test/resources/pyyaml/spec-07-09.canonical9
-rw-r--r--src/test/resources/pyyaml/spec-07-09.data11
-rw-r--r--src/test/resources/pyyaml/spec-07-10.canonical15
-rw-r--r--src/test/resources/pyyaml/spec-07-10.data11
-rw-r--r--src/test/resources/pyyaml/spec-07-11.data2
-rw-r--r--src/test/resources/pyyaml/spec-07-12a.canonical6
-rw-r--r--src/test/resources/pyyaml/spec-07-12a.data3
-rw-r--r--src/test/resources/pyyaml/spec-07-12b.canonical3
-rw-r--r--src/test/resources/pyyaml/spec-07-12b.data4
-rw-r--r--src/test/resources/pyyaml/spec-07-13.canonical9
-rw-r--r--src/test/resources/pyyaml/spec-07-13.data9
-rw-r--r--src/test/resources/pyyaml/spec-08-01.canonical8
-rw-r--r--src/test/resources/pyyaml/spec-08-01.data2
-rw-r--r--src/test/resources/pyyaml/spec-08-02.canonical8
-rw-r--r--src/test/resources/pyyaml/spec-08-02.data2
-rw-r--r--src/test/resources/pyyaml/spec-08-03.canonical6
-rw-r--r--src/test/resources/pyyaml/spec-08-03.data2
-rw-r--r--src/test/resources/pyyaml/spec-08-04.data2
-rw-r--r--src/test/resources/pyyaml/spec-08-05.canonical7
-rw-r--r--src/test/resources/pyyaml/spec-08-05.data5
-rw-r--r--src/test/resources/pyyaml/spec-08-06.data5
-rw-r--r--src/test/resources/pyyaml/spec-08-07.canonical8
-rw-r--r--src/test/resources/pyyaml/spec-08-07.data4
-rw-r--r--src/test/resources/pyyaml/spec-08-08.canonical15
-rw-r--r--src/test/resources/pyyaml/spec-08-08.data13
-rw-r--r--src/test/resources/pyyaml/spec-08-09.canonical21
-rw-r--r--src/test/resources/pyyaml/spec-08-09.data11
-rw-r--r--src/test/resources/pyyaml/spec-08-10.canonical23
-rw-r--r--src/test/resources/pyyaml/spec-08-10.data15
-rw-r--r--src/test/resources/pyyaml/spec-08-11.canonical8
-rw-r--r--src/test/resources/pyyaml/spec-08-11.data2
-rw-r--r--src/test/resources/pyyaml/spec-08-12.canonical10
-rw-r--r--src/test/resources/pyyaml/spec-08-12.data8
-rw-r--r--src/test/resources/pyyaml/spec-08-13.canonical10
-rw-r--r--src/test/resources/pyyaml/spec-08-13.data4
-rw-r--r--src/test/resources/pyyaml/spec-08-14.canonical10
-rw-r--r--src/test/resources/pyyaml/spec-08-14.data5
-rw-r--r--src/test/resources/pyyaml/spec-08-15.canonical11
-rw-r--r--src/test/resources/pyyaml/spec-08-15.data5
-rw-r--r--src/test/resources/pyyaml/spec-09-01.canonical11
-rw-r--r--src/test/resources/pyyaml/spec-09-01.data6
-rw-r--r--src/test/resources/pyyaml/spec-09-02.canonical7
-rw-r--r--src/test/resources/pyyaml/spec-09-02.data6
-rw-r--r--src/test/resources/pyyaml/spec-09-03.canonical7
-rw-r--r--src/test/resources/pyyaml/spec-09-03.data6
-rw-r--r--src/test/resources/pyyaml/spec-09-04.canonical6
-rw-r--r--src/test/resources/pyyaml/spec-09-04.data4
-rw-r--r--src/test/resources/pyyaml/spec-09-05.canonical7
-rw-r--r--src/test/resources/pyyaml/spec-09-05.data8
-rw-r--r--src/test/resources/pyyaml/spec-09-06.canonical3
-rw-r--r--src/test/resources/pyyaml/spec-09-06.data1
-rw-r--r--src/test/resources/pyyaml/spec-09-07.canonical11
-rw-r--r--src/test/resources/pyyaml/spec-09-07.data6
-rw-r--r--src/test/resources/pyyaml/spec-09-08.canonical6
-rw-r--r--src/test/resources/pyyaml/spec-09-08.data1
-rw-r--r--src/test/resources/pyyaml/spec-09-09.canonical7
-rw-r--r--src/test/resources/pyyaml/spec-09-09.data6
-rw-r--r--src/test/resources/pyyaml/spec-09-10.canonical5
-rw-r--r--src/test/resources/pyyaml/spec-09-10.data3
-rw-r--r--src/test/resources/pyyaml/spec-09-11.canonical6
-rw-r--r--src/test/resources/pyyaml/spec-09-11.data5
-rw-r--r--src/test/resources/pyyaml/spec-09-12.canonical12
-rw-r--r--src/test/resources/pyyaml/spec-09-12.data8
-rw-r--r--src/test/resources/pyyaml/spec-09-13.canonical11
-rw-r--r--src/test/resources/pyyaml/spec-09-13.data6
-rw-r--r--src/test/resources/pyyaml/spec-09-14.data14
-rw-r--r--src/test/resources/pyyaml/spec-09-15.canonical18
-rw-r--r--src/test/resources/pyyaml/spec-09-15.data13
-rw-r--r--src/test/resources/pyyaml/spec-09-16.canonical6
-rw-r--r--src/test/resources/pyyaml/spec-09-16.data3
-rw-r--r--src/test/resources/pyyaml/spec-09-17.canonical4
-rw-r--r--src/test/resources/pyyaml/spec-09-17.data3
-rw-r--r--src/test/resources/pyyaml/spec-09-18.canonical8
-rw-r--r--src/test/resources/pyyaml/spec-09-18.data9
-rw-r--r--src/test/resources/pyyaml/spec-09-19.canonical6
-rw-r--r--src/test/resources/pyyaml/spec-09-19.data4
-rw-r--r--src/test/resources/pyyaml/spec-09-20.canonical8
-rw-r--r--src/test/resources/pyyaml/spec-09-20.data11
-rw-r--r--src/test/resources/pyyaml/spec-09-21.data8
-rw-r--r--src/test/resources/pyyaml/spec-09-22.canonical10
-rw-r--r--src/test/resources/pyyaml/spec-09-22.data4
-rw-r--r--src/test/resources/pyyaml/spec-09-23.canonical10
-rw-r--r--src/test/resources/pyyaml/spec-09-23.data11
-rw-r--r--src/test/resources/pyyaml/spec-09-24.canonical10
-rw-r--r--src/test/resources/pyyaml/spec-09-24.data6
-rw-r--r--src/test/resources/pyyaml/spec-09-25.canonical4
-rw-r--r--src/test/resources/pyyaml/spec-09-25.data3
-rw-r--r--src/test/resources/pyyaml/spec-09-26.canonical3
-rw-r--r--src/test/resources/pyyaml/spec-09-26.data8
-rw-r--r--src/test/resources/pyyaml/spec-09-27.canonical3
-rw-r--r--src/test/resources/pyyaml/spec-09-27.data8
-rw-r--r--src/test/resources/pyyaml/spec-09-28.canonical3
-rw-r--r--src/test/resources/pyyaml/spec-09-28.data8
-rw-r--r--src/test/resources/pyyaml/spec-09-29.canonical4
-rw-r--r--src/test/resources/pyyaml/spec-09-29.data4
-rw-r--r--src/test/resources/pyyaml/spec-09-30.canonical7
-rw-r--r--src/test/resources/pyyaml/spec-09-30.data14
-rw-r--r--src/test/resources/pyyaml/spec-09-31.canonical7
-rw-r--r--src/test/resources/pyyaml/spec-09-31.data14
-rw-r--r--src/test/resources/pyyaml/spec-09-32.canonical7
-rw-r--r--src/test/resources/pyyaml/spec-09-32.data14
-rw-r--r--src/test/resources/pyyaml/spec-09-33.canonical7
-rw-r--r--src/test/resources/pyyaml/spec-09-33.data14
-rw-r--r--src/test/resources/pyyaml/spec-10-01.canonical12
-rw-r--r--src/test/resources/pyyaml/spec-10-01.data2
-rw-r--r--src/test/resources/pyyaml/spec-10-02.canonical14
-rw-r--r--src/test/resources/pyyaml/spec-10-02.data8
-rw-r--r--src/test/resources/pyyaml/spec-10-03.canonical12
-rw-r--r--src/test/resources/pyyaml/spec-10-03.data4
-rw-r--r--src/test/resources/pyyaml/spec-10-04.canonical11
-rw-r--r--src/test/resources/pyyaml/spec-10-04.data4
-rw-r--r--src/test/resources/pyyaml/spec-10-05.canonical14
-rw-r--r--src/test/resources/pyyaml/spec-10-05.data7
-rw-r--r--src/test/resources/pyyaml/spec-10-06.canonical16
-rw-r--r--src/test/resources/pyyaml/spec-10-06.data2
-rw-r--r--src/test/resources/pyyaml/spec-10-07.canonical16
-rw-r--r--src/test/resources/pyyaml/spec-10-07.data7
-rw-r--r--src/test/resources/pyyaml/spec-10-08.data5
-rw-r--r--src/test/resources/pyyaml/spec-10-09.canonical8
-rw-r--r--src/test/resources/pyyaml/spec-10-09.data4
-rw-r--r--src/test/resources/pyyaml/spec-10-10.canonical16
-rw-r--r--src/test/resources/pyyaml/spec-10-10.data8
-rw-r--r--src/test/resources/pyyaml/spec-10-11.canonical24
-rw-r--r--src/test/resources/pyyaml/spec-10-11.data7
-rw-r--r--src/test/resources/pyyaml/spec-10-12.canonical9
-rw-r--r--src/test/resources/pyyaml/spec-10-12.data3
-rw-r--r--src/test/resources/pyyaml/spec-10-13.canonical11
-rw-r--r--src/test/resources/pyyaml/spec-10-13.data5
-rw-r--r--src/test/resources/pyyaml/spec-10-14.canonical11
-rw-r--r--src/test/resources/pyyaml/spec-10-14.data4
-rw-r--r--src/test/resources/pyyaml/spec-10-15.canonical18
-rw-r--r--src/test/resources/pyyaml/spec-10-15.data3
-rw-r--r--src/test/resources/pyyaml/str.data1
-rw-r--r--src/test/resources/pyyaml/tags.events12
-rw-r--r--src/test/resources/pyyaml/test_mark.marks38
-rw-r--r--src/test/resources/pyyaml/timestamp-bugs.data6
-rw-r--r--src/test/resources/pyyaml/timestamp.data5
-rw-r--r--src/test/resources/pyyaml/unacceptable-key.loader-error4
-rw-r--r--src/test/resources/pyyaml/unclosed-bracket.loader-error6
-rw-r--r--src/test/resources/pyyaml/unclosed-quoted-scalar.loader-error2
-rw-r--r--src/test/resources/pyyaml/undefined-anchor.loader-error3
-rw-r--r--src/test/resources/pyyaml/undefined-constructor.loader-error1
-rw-r--r--src/test/resources/pyyaml/undefined-tag-handle.loader-error1
-rw-r--r--src/test/resources/pyyaml/unsupported-version.emitter-error5
-rw-r--r--src/test/resources/pyyaml/value.data1
-rw-r--r--src/test/resources/pyyaml/yaml.data3
-rw-r--r--src/test/resources/reader/unicode-16be.txtbin0 -> 10 bytes
-rw-r--r--src/test/resources/reader/unicode-16le.txtbin0 -> 10 bytes
-rw-r--r--src/test/resources/reader/utf-8.txt1
-rw-r--r--src/test/resources/specification/example2_1.yaml3
-rw-r--r--src/test/resources/specification/example2_10.yaml8
-rw-r--r--src/test/resources/specification/example2_11.yaml9
-rw-r--r--src/test/resources/specification/example2_12.yaml8
-rw-r--r--src/test/resources/specification/example2_13.yaml4
-rw-r--r--src/test/resources/specification/example2_14.yaml4
-rw-r--r--src/test/resources/specification/example2_15.yaml8
-rw-r--r--src/test/resources/specification/example2_16.yaml7
-rw-r--r--src/test/resources/specification/example2_17.yaml7
-rw-r--r--src/test/resources/specification/example2_17_control.yaml2
-rw-r--r--src/test/resources/specification/example2_17_hexesc.yaml2
-rw-r--r--src/test/resources/specification/example2_17_quoted.yaml2
-rw-r--r--src/test/resources/specification/example2_17_single.yaml1
-rw-r--r--src/test/resources/specification/example2_17_tie_fighter.yaml1
-rw-r--r--src/test/resources/specification/example2_17_unicode.yaml2
-rw-r--r--src/test/resources/specification/example2_18.yaml6
-rw-r--r--src/test/resources/specification/example2_19.yaml5
-rw-r--r--src/test/resources/specification/example2_2.yaml3
-rw-r--r--src/test/resources/specification/example2_20.yaml6
-rw-r--r--src/test/resources/specification/example2_21.yaml4
-rw-r--r--src/test/resources/specification/example2_22.yaml4
-rw-r--r--src/test/resources/specification/example2_23.yaml14
-rw-r--r--src/test/resources/specification/example2_23_application.yaml5
-rw-r--r--src/test/resources/specification/example2_23_non_date.yaml3
-rw-r--r--src/test/resources/specification/example2_23_picture.yaml9
-rw-r--r--src/test/resources/specification/example2_24.yaml14
-rw-r--r--src/test/resources/specification/example2_24_dumped.yaml11
-rw-r--r--src/test/resources/specification/example2_25.yaml7
-rw-r--r--src/test/resources/specification/example2_26.yaml7
-rw-r--r--src/test/resources/specification/example2_27.yaml29
-rw-r--r--src/test/resources/specification/example2_27_dumped.yaml18
-rw-r--r--src/test/resources/specification/example2_28.yaml29
-rw-r--r--src/test/resources/specification/example2_3.yaml8
-rw-r--r--src/test/resources/specification/example2_4.yaml8
-rw-r--r--src/test/resources/specification/example2_5.yaml3
-rw-r--r--src/test/resources/specification/example2_6.yaml5
-rw-r--r--src/test/resources/specification/example2_7.yaml10
-rw-r--r--src/test/resources/specification/example2_8.yaml10
-rw-r--r--src/test/resources/specification/example2_9.yaml8
-rw-r--r--src/test/resources/specification/types/map.yaml6
-rw-r--r--src/test/resources/specification/types/map_mixed_tags.yaml6
-rw-r--r--src/test/resources/specification/types/merge.yaml27
-rw-r--r--src/test/resources/specification/types/omap.yaml8
-rw-r--r--src/test/resources/specification/types/pairs.yaml7
-rw-r--r--src/test/resources/specification/types/seq.yaml14
-rw-r--r--src/test/resources/specification/types/set.yaml7
-rw-r--r--src/test/resources/specification/types/v.yaml4
-rw-r--r--src/test/resources/specification/types/value.yaml10
676 files changed, 23440 insertions, 0 deletions
diff --git a/.classpath b/.classpath
new file mode 100644
index 00000000..7e665fe5
--- /dev/null
+++ b/.classpath
@@ -0,0 +1,10 @@
+<classpath>
+ <classpathentry kind="src" path="src/main/java"/>
+ <classpathentry kind="src" path="src/test/java"/>
+ <classpathentry kind="src" path="src/test/resources" excluding="**/*.java"/>
+ <classpathentry kind="output" path="bin"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="var" path="M2_REPO/commons-logging/commons-logging/1.1.1/commons-logging-1.1.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/junit/junit/3.8.2/junit-3.8.2.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/springframework/spring/2.5.6/spring-2.5.6.jar"/>
+</classpath> \ No newline at end of file
diff --git a/.hgignore b/.hgignore
new file mode 100644
index 00000000..7d6abe2e
--- /dev/null
+++ b/.hgignore
@@ -0,0 +1,5 @@
+
+syntax: regexp
+^target$
+^bin$
+^\.settings$
diff --git a/.hgtags b/.hgtags
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/.hgtags
diff --git a/.project b/.project
new file mode 100644
index 00000000..c975a15e
--- /dev/null
+++ b/.project
@@ -0,0 +1,13 @@
+<projectDescription>
+ <name>SnakeYAML</name>
+ <comment>YAML 1.1 parser and emitter for Java</comment>
+ <projects/>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription> \ No newline at end of file
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 00000000..db6435d1
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,21 @@
+SnakeYAML was created in late 2008 with an intention
+to implement a reference YAML parser for Java.
+
+The PRIMARY AUTHORS are (and/or have been):
+
+* Andrey Somov <py4fun@gmail.com>
+
+And here is an inevitably incomplete list of MUCH-APPRECIATED CONTRIBUTORS --
+people who have submitted patches, reported bugs, helped
+answer newbie questions, and generally made SnakeYAML that much better:
+
+Kirill Simonov <xi@resolvent.net> - writing the original Python code.
+Ola Bini <ola@ologix.com>
+kirkz at sourceforge
+tailwaggers at sourceforge
+jberry at sourceforge
+jscheid37 at sourceforge
+Red Forks at gmail
+Nathan Sweet
+James Nissel
+Christophe Desguez
diff --git a/Eclipse-format.xml b/Eclipse-format.xml
new file mode 100644
index 00000000..9717b7da
--- /dev/null
+++ b/Eclipse-format.xml
@@ -0,0 +1,264 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<profiles version="11">
+<profile kind="CodeFormatterProfile" name="SnakeYAML" version="11">
+<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="0"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression" value="80"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_binary_operator" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="2"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_binary_operator" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="0"/>
+<setting id="org.eclipse.jdt.core.compiler.source" value="1.5"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.format_line_comments" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.align_type_members_on_columns" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="100"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration" value="0"/>
+<setting id="org.eclipse.jdt.core.formatter.indentation.size" value="4"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_assignment" value="0"/>
+<setting id="org.eclipse.jdt.core.compiler.problem.assertIdentifier" value="error"/>
+<setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="space"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.compiler.problem.enumIdentifier" value="error"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="4"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_empty_lines" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression" value="16"/>
+<setting id="org.eclipse.jdt.core.compiler.compliance" value="1.5"/>
+<setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_binary_expression" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.format_javadoc_comments" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="80"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_import_groups" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="0"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.wrap_before_binary_operator" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.format_html" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.format_source_code" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="insert"/>
+<setting id="org.eclipse.jdt.core.compiler.codegen.targetPlatform" value="1.5"/>
+<setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="0"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line" value="false"/>
+</profile>
+</profiles>
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 00000000..f52fb68c
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2008
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README b/README
new file mode 100644
index 00000000..89946685
--- /dev/null
+++ b/README
@@ -0,0 +1,233 @@
+= SnakeYAML =
+
+'''SnakeYAML is a YAML parser and emitter for Java.'''
+
+
+== Overview ==
+
+[http://yaml.org/ YAML] is a data serialization format designed for human
+readability and interaction with scripting languages.
+
+[http://pyyaml.org/wiki/SnakeYAML SnakeYAML] is a YAML parser and emitter for
+the Java programming language. SnakeYAML tries to be as close as possible to PyYAML
+API allowing documents to be easily exchanged between Python and Java.
+
+SnakeYAML features
+
+ * a '''complete''' [http://yaml.org/spec/current.html YAML 1.1] parser.
+ In particular, SnakeYAML can parse all examples from the specification.
+ * Unicode support including UTF-8/UTF-16 input/output.
+ * high-level API for serializing and deserializing native Java objects.
+ * support for all types from the [http://yaml.org/type/index.html YAML types repository].
+ * relatively sensible error messages.
+
+Note that SnakeYAML is still young and may have some bugs.
+
+== Requirements ==
+
+SnakeYAML requires Java 5 or higher.
+
+
+== Download and Installation ==
+
+The current stable release of SnakeYAML: '''1.1'''.
+
+Download links:
+
+ * '''source''': http://www.assembla.com/spaces/snakeyaml/trac_mercurial_tool
+ * '''JAR package''': http://snakeyamlrepo.appspot.com/repository/SnakeYAML/SnakeYAML/1.1/SnakeYAML-1.1.jar
+ * '''ZIP archive''': http://www.assembla.com/spaces/snakeyaml/documents/bK10C2_Aur3AHfeJe5afGb/download?filename=SnakeYAML-all-1.1.zip
+ * '''Repository''': http://snakeyamlrepo.appspot.com/
+
+Browse 1.1 reports:
+
+ * '''Maven generated report''': http://snakeyamlrepo.appspot.com/releases/1.1/site/index.html
+ * '''Project's report''': http://snakeyamlrepo.appspot.com/releases/1.1/site/project-reports.html
+ * '''Javadocs''': http://snakeyamlrepo.appspot.com/releases/1.1/site/apidocs/index.html
+ * '''Changes report''': http://snakeyamlrepo.appspot.com/releases/1.1/site/changes-report.html
+ * '''Maven generated report''': http://snakeyamlrepo.appspot.com/releases/1.1/site/index.html
+ * '''Test coverage report''': http://snakeyamlrepo.appspot.com/releases/1.1/site/cobertura/index.html
+
+Maven 2 configuration:
+
+Repository definition (in settings.xml)
+{{{
+<repositories>
+ ...
+ <repository>
+ <id>snakeyaml</id>
+ <name>SnakeYAML repository</name>
+ <url>http://snakeyamlrepo.appspot.com/repository</url>
+ </repository>
+ ...
+</repositories>
+}}}
+
+Dependency definition (in pom.xml)
+{{{
+<dependencies>
+ ...
+ <dependency>
+ <groupId>SnakeYAML</groupId>
+ <artifactId>SnakeYAML</artifactId>
+ <version>1.1</version>
+ </dependency>
+ ...
+</dependencies>
+}}}
+
+== Documentation ==
+
+''Loading:''
+{{{
+Yaml yaml = new Yaml();
+Object obj = yaml.load("a: 1\nb: 2\nc:\n - aaa\n - bbb");
+System.out.println(obj);
+
+{b=2, c=[aaa, bbb], a=1}
+}}}
+''Dumping:''
+{{{
+
+Map<String, String> map = new HashMap<String, String>();
+map.put("name", "Pushkin");
+Yaml yaml = new Yaml();
+String output = yaml.dump(map);
+System.out.println(output);
+
+---
+name: Pushkin
+}}}
+
+For more details, please check [wiki:Documentation SnakeYAML Documentation].
+
+
+== History ==
+'''1.1 (2009-03-14)'''
+ * test coverage reached 98%
+ * byte[] is used for type `binary`
+ * Better Spring support: the root `JavaBean` class can be specified as a String
+ * Performance: fix a bug with expanding Regular Expressions (thanks to Christophe Desguez)
+ * Fix ticket #4: java.sql.Date was not handled properly (thanks to Christophe Desguez)
+ * Introduce `Enums` in `DumperOptions`
+ * minor refactoring and bug fixes
+ * add [/snakeyaml/wiki/Documentation#Threading Threads] and
+ [/snakeyaml/wiki/Documentation#Spring Spring] sections to the wiki documentation
+
+'''1.0.1 (2009-02-18)'''
+ * proper `Enum` [http://trac-hg.assembla.com/snakeyaml/wiki/Documentation#Enum support] (thanks to James Nissel)
+ * minor performance improvement
+ * fix minor issues in `DumperOptions`
+
+'''1.0 (2009-02-06)'''
+ * Use `LinkedHashMap` to respect the order where it is required (`ScannerImpl`.java and Emitter.java)
+ * The mailing list is renamed to `snakeyaml-core` to avoid a name conflict in `Google` `AppEngine`
+
+'''1.0rc2 (2009-01-22)'''
+ * add [http://trac-hg.assembla.com/snakeyaml/wiki/Documentation#JavaBeans JavaBeans section] to the wiki
+ * Provide possibility to define/eliminate the root tag for `JavaBeans`
+ * Arrays as `JavaBens` properties are properly supported
+ * Do not emit redundant tags for `JavaBeans`
+ * Respect public fields in `JavaBeans`
+
+'''1.0rc1 (2009-01-16)'''
+ * Implement [http://trac-hg.assembla.com/snakeyaml/wiki/Documentation#Typesafecollections type safe List and Map]
+ as a property of a custom Java class
+ * remove Java 6 dependencies
+
+'''0.91 (2009-01-14)'''
+ * Support [http://trac-hg.assembla.com/snakeyaml/wiki/Documentation#Shortcuts shortcut tags] for custom classes
+ * Import canonical scanner and parser from PyYAML
+
+'''0.9 (2009-01-12)'''
+ * Minor changes
+ * Add possibility [http://trac-hg.assembla.com/snakeyaml/wiki/Documentation#Providingthetopleveltype to provide] the top level type
+ * Fix a bug in Emitter when writing folded scalars
+
+'''0.8 (2009-01-07)'''
+ * Add possibility to use java.io.Reader as input
+ * import changes from [http://pyyaml.org/wiki/PyYAML#History PyYAML 3.07/3.08]
+ * Use global tags (with !!) to load/dump Java custom classes
+ * Fix parsing Long.MIN_VALUE
+ * when constructing integers try to create the first in the following order:
+ Integer -> Long -> `BigInteger`
+
+'''0.7 (2008-12-20)'''
+ * improve test coverage
+
+'''0.6 (2008-12-17)'''
+ * add more examples to the documentation
+ * Public interface is using Iterator instead of Iterable
+ * Sort names when `JavaBeans` are represented
+ * defaultFlowStyle for Dumper is configurable in `DumperOptions`
+
+'''0.5 (2008-12-12)'''
+ * Add possibility to define an implicit resolver
+ * Add possibility to define an explicit constructor
+ * Java objects can be constructed from mapping (javabean), from sequence (constructor),
+ from scalar (constructor)
+ * fix omap and pairs tags
+ * Implement possibility to define a custom List or Map implementation
+ * Implement possibility to define a custom Representer
+ * Support arrays of reference types
+ * Import latest changes from PyYAML (after 3.06 was released)
+ * Fix Node identity to avoid aliases for simple types - [1, 1]
+ * Recursive objects can be represented (but not yet constructed)
+ * Binary is represented back as String
+ * Fix: 'null' can be a key in a map
+ * Fix: 'set' type works
+
+'''0.4 (2008-11-11)'''
+ * Fix a deviation with PyYAML in method scanBlockScalar().
+ Fix a bug in [https://jvyaml.dev.java.net/ JvYaml] that the trailing '\n' in a
+ block scalar was removed
+ * Restore from PyYAML the way the keys are parsed. (Restored methods are
+ stalePossibleSimpleKeys() and removePossibleSimpleKey().)
+ Fix issue http://code.google.com/p/jvyamlb/issues/detail?id=6
+ * Change public interface. Rename YAML to Yaml. Remove all static methods from Yaml.
+ Factory and configuration must be injected at the constructor.
+ Yaml loadAll() and dumpAll() methods work with Iterable instead of List.
+ This way is closer to PyYAML API
+ * Reader as in PyYAML is implemented. BOM is properly supported. Fix a known [http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058 bug] in Java
+ * Fix issue: https://jvyaml.dev.java.net/issues/show_bug.cgi?id=11
+ * Respect Unicode characters.
+ Fix issue: https://jvyaml.dev.java.net/issues/show_bug.cgi?id=10
+ * Respect sign for float.
+ Fix issue: https://jvyaml.dev.java.net/issues/show_bug.cgi?id=13
+ * Binary data is represented as [http://java.sun.com/javase/6/docs/api/java/nio/ByteBuffer.html ByteBuffer]
+ * When parsed, a timestamp in the canonical form (i.e, 2001-12-15T02:59:43.1Z) is
+ interpreted as if it is in the default time zone.
+ Fix issue: https://jvyaml.dev.java.net/issues/show_bug.cgi?id=7
+ * Restore Mark from PyYAML to show a snippet of YAML in case of invalid data
+ * Reformat the source files and provide formatter for Eclipse
+ * Mavenize the project and apply Maven standard folder structure
+ * Import [https://jvyaml.dev.java.net JvYaml] source from CVS to Mercurial
+
+== Development and bug reports ==
+
+You may check out the SnakeYAML source code from
+[http://hg.assembla.com/snakeyaml SnakeYAML Mercurial repository].
+
+You may also
+[http://trac-hg.assembla.com/snakeyaml/browser browse] the SnakeYAML source code.
+
+If you find a bug in SnakeYAML, please
+[http://trac-hg.assembla.com/snakeyaml/newticket file a bug report].
+You may review open bugs through
+[http://trac-hg.assembla.com/snakeyaml/report/1 the list of open tickets].
+
+You may discuss SnakeYAML at
+[http://groups.google.com/group/snakeyaml-core the mailing list].
+
+== TODO ==
+ * proper `enum` support
+
+== Known bugs ==
+ * Recursive objects are not fully supported. Dumping works but loading does not.
+
+== Author and copyright ==
+
+The SnakeYAML is developed by Andrey Somov and it is based on [http://pyyaml.org/wiki/PyYAML PyYAML]
+module written by [mailto:xi@resolvent.net Kirill Simonov].
+
+SnakeYAML is released under the MIT license.
diff --git a/announcement.msg b/announcement.msg
new file mode 100644
index 00000000..39d77a49
--- /dev/null
+++ b/announcement.msg
@@ -0,0 +1,58 @@
+From: Andrey Somov <py4fun@gmail.com>
+To: yaml-core@lists.sourceforge.net
+Subject: [ANN] SnakeYAML-1.1: improve performance and test coverage
+
+=============================
+ Announcing SnakeYAML-1.1
+=============================
+
+A new release of SnakeYAML is now available:
+
+ http://trac-hg.assembla.com/snakeyaml/
+
+This release delivers a significant performance improvements as well as minor changes
+and bug fixes.
+
+Changes
+=======
+ * test coverage reached 98%
+ * Better Spring support: the root JavaBean class to parse can be specified as a String
+ * Performance: fix a bug with expanding Regular Expressions
+ * Fix ticket #4: java.sql.Date was not handled properly
+ * Introduce Enums in DumperOptions
+ * minor bug fixes
+
+Resources
+=========
+
+SnakeYAML homepage: http://trac-hg.assembla.com/snakeyaml/
+SnakeYAML documentation: http://trac-hg.assembla.com/snakeyaml/wiki/Documentation
+
+JAR package: http://snakeyamlrepo.appspot.com/repository/SnakeYAML/SnakeYAML/1.1/SnakeYAML-1.1.jar
+Reports: http://snakeyamlrepo.appspot.com/
+
+SnakeYAML Mercurial repository: http://hg.assembla.com/snakeyaml
+Submit a bug report: http://trac-hg.assembla.com/snakeyaml/newticket
+
+YAML homepage: http://yaml.org/
+YAML-core mailing list: http://lists.sourceforge.net/lists/listinfo/yaml-core
+
+
+About SnakeYAML
+============
+
+YAML is a data serialization format designed for human readability and
+interaction with scripting languages. SnakeYAML is a YAML parser and
+emitter for Java.
+
+SnakeYAML features a complete YAML 1.1 parser.
+SnakeYAML is applicable for a broad range of tasks from complex
+configuration files to object serialization and persistence.
+
+
+Copyright
+=========
+
+SnakeYAML is developed by Andrey Somov <py4fun@gmail.com>.
+
+SnakeYAML is released under the MIT license.
diff --git a/doc/wiki/Documentation.txt b/doc/wiki/Documentation.txt
new file mode 100644
index 00000000..93de3702
--- /dev/null
+++ b/doc/wiki/Documentation.txt
@@ -0,0 +1,1335 @@
+= SnakeYAML Documentation =
+
+''This documentation is very brief and incomplete. Feel free to fix or improve it.''
+
+
+[[PageOutline]]
+
+
+== Installation ==
+
+Download the source package and put it to the classpath.
+
+Note that there are some subtle (but not really significant) differences between [http://pyyaml.org/wiki/PyYAML Python] and [http://trac-hg.assembla.com/snakeyaml/wiki SnakeYaml] parsers
+and emitters.
+
+== Frequently Asked Questions ==
+
+=== Dictionaries without nested collections are not dumped correctly ===
+
+''Why does''
+{{{
+Yaml yaml = new Yaml();
+String document = " a: 1\n b:\n c: 3\n d: 4\n";
+System.out.println(document);
+System.out.println(yaml.dump(yaml.load(document)));
+}}}
+''give''
+{{{
+ a: 1
+ b:
+ c: 3
+ d: 4
+
+a: 1
+b: {c: 3, d: 4}
+}}}
+
+It's a correct output despite the fact that the style of the nested mapping is different.
+
+By default, SnakeYAML chooses the style of a collection depending on whether it has nested
+collections. If a collection has nested collections, it will be assigned the block style.
+Otherwise it will have the flow style.
+
+If you want collections to be always serialized in the block style, set the parameter
+'''`defaultFlowStyle`''' of '''`DumperOptions`''' to '''`block`'''. For instance,
+{{{
+DumperOptions options = new DumperOptions();
+options.setDefaultFlowStyle(DumperOptions.DefaultFlowStyle.BLOCK);
+Yaml yaml = new Yaml(options);
+String document = " a: 1\n b:\n c: 3\n d: 4\n";
+System.out.println(yaml.dump(yaml.load(document)));
+
+a: 1
+b:
+ c: 3
+ d: 4
+}}}
+
+You can find an example [http://trac-hg.assembla.com/snakeyaml/browser/src/test/java/examples/CollectionStyleTest.java here]
+
+=== Binary Data ===
+`byte[]` is represented as binary. Also when a `String` contains at least one non-printable character the
+`!!binary` type is emitted.
+
+Binary scalar is parsed as `byte[]`.
+
+An example can found [http://trac-hg.assembla.com/snakeyaml/browser/src/test/java/org/yaml/snakeyaml/types/BinaryTagTest.java here].
+
+== Tutorial ==
+
+Start with instantiating the '''`org.yaml.snakeyaml.Yaml`''' instance.
+
+{{{
+Yaml yaml = new Yaml();
+}}}
+
+
+=== Loading YAML ===
+
+The method '''`Yaml.load()`''' converts a YAML document to a Java object.
+
+{{{
+Yaml yaml = new Yaml();
+String document = "\n- Hesperiidae\n- Papilionidae\n- Apatelodidae\n- Epiplemidae";
+List<String> list = (List<String>) yaml.load(document);
+System.out.println(list);
+
+['Hesperiidae', 'Papilionidae', 'Apatelodidae', 'Epiplemidae']
+}}}
+You can find an example [http://trac-hg.assembla.com/snakeyaml/browser/src/test/java/examples/LoadExampleTest.java here]
+
+'''`Yaml.load()`''' accepts a String or
+an `InputStream` object. '''`Yaml.load(InputStream stream)`''' detects the encoding
+by checking the '''BOM''' (byte order mark) sequence at the beginning of the
+stream. If no '''BOM''' is present, the '''utf-8''' encoding is assumed.
+
+'''`Yaml.load()`''' returns a Java object.
+
+{{{
+public void testLoadFromString() {
+ Yaml yaml = new Yaml();
+ String document = "hello: 25";
+ Map map = (Map) yaml.load(document);
+ assertEquals("{hello=25}", map.toString());
+ assertEquals(new Long(25), map.get("hello"));
+}
+
+public void testLoadFromStream() throws FileNotFoundException {
+ InputStream input = new FileInputStream(new File("src/test/resources/reader/utf-8.txt"));
+ Yaml yaml = new Yaml();
+ Object data = yaml.load(input);
+ assertEquals("test", data);
+ //
+ data = yaml.load(new ByteArrayInputStream("test2".getBytes()));
+ assertEquals("test2", data);
+}
+}}}
+
+If a String or a stream contains several documents, you may load them all with the
+'''`Yaml.loadAll()`''' method.
+{{{
+---
+Time: 2001-11-23 15:01:42 -5
+User: ed
+Warning:
+ This is an error message
+ for the log file
+---
+Time: 2001-11-23 15:02:31 -5
+User: ed
+Warning:
+ A slightly different error
+ message.
+---
+Date: 2001-11-23 15:03:17 -5
+User: ed
+Fatal:
+ Unknown variable "bar"
+Stack:
+ - file: TopClass.py
+ line: 23
+ code: |
+ x = MoreObject("345\n")
+ - file: MoreClass.py
+ line: 58
+ code: |-
+ foo = bar
+}}}
+{{{
+public void testLoadManyDocuments() throws FileNotFoundException {
+ InputStream input = new FileInputStream(new File(
+ "src/test/resources/specification/example2_28.yaml"));
+ Yaml yaml = new Yaml();
+ int counter = 0;
+ for (Object data : yaml.loadAll(input)) {
+ System.out.println(data);
+ counter++;
+ }
+ assertEquals(3, counter);
+}
+}}}
+{{{
+{Time=Fri Nov 23 21:01:42 CET 2001, User=ed, Warning=This is an error message for the log file}
+{Time=Fri Nov 23 21:02:31 CET 2001, User=ed, Warning=A slightly different error message.}
+{Date=Fri Nov 23 21:03:17 CET 2001, User=ed, Fatal=Unknown variable "bar", Stack=[{file=TopClass.py, line=23, code=x = MoreObject("345\n")
+}, {file=MoreClass.py, line=58, code=foo = bar}]}
+}}}
+
+SnakeYAML allows you [http://trac-hg.assembla.com/snakeyaml/browser/src/test/java/examples/AnyObjectExampleTest.java to construct] a Java object of any type.
+
+{{{
+none: [~, null]
+bool: [true, false, on, off]
+int: 42
+float: 3.14159
+list: [LITE, RES_ACID, SUS_DEXT]
+dict: {hp: 13, sp: 5}
+}}}
+
+{{{
+public void testLoad() throws IOException {
+ String doc = Util.getLocalResource("examples/any-object-example.yaml");
+ Yaml yaml = new Yaml();
+ Map<String, Object> object = (Map<String, Object>) yaml.load(doc);
+ System.out.println(object);
+}
+}}}
+{{{
+{none=[null, null], bool=[true, false, true, false], int=42, float=3.14159,
+list=[LITE, RES_ACID, SUS_DEXT], dict={hp=13, sp=5}}
+}}}
+
+Even instances of custom Java classes [http://trac-hg.assembla.com/snakeyaml/browser/src/test/java/org/yaml/snakeyaml/constructor/ConstructorTest.java can be constructed].
+{{{
+/**
+ * create JavaBean
+ */
+public void testGetBeanAssumeClass() {
+ String data = "--- !org.yaml.snakeyaml.constructor.Person\nfirstName: Andrey\nage: 99";
+ Object obj = construct(data);
+ assertNotNull(obj);
+ assertTrue("Unexpected: " + obj.getClass().toString(), obj instanceof Person);
+ Person person = (Person) obj;
+ assertEquals("Andrey", person.getFirstName());
+ assertNull(person.getLastName());
+ assertEquals(99, person.getAge().intValue());
+}
+
+/**
+ * create instance using constructor arguments
+ */
+public void testGetConstructorBean() {
+ String data = "--- !org.yaml.snakeyaml.constructor.Person [ Andrey, Somov, 99 ]";
+ Object obj = construct(data);
+ assertNotNull(obj);
+ assertTrue(obj.getClass().toString(), obj instanceof Person);
+ Person person = (Person) obj;
+ assertEquals("Andrey", person.getFirstName());
+ assertEquals("Somov", person.getLastName());
+ assertEquals(99, person.getAge().intValue());
+}
+
+/**
+ * create instance using scalar argument
+ */
+public void testGetConstructorFromScalar() {
+ String data = "--- !org.yaml.snakeyaml.constructor.Person 'Somov'";
+ Object obj = construct(data);
+ assertNotNull(obj);
+ assertTrue(obj.getClass().toString(), obj instanceof Person);
+ Person person = (Person) obj;
+ assertNull("Andrey", person.getFirstName());
+ assertEquals("Somov", person.getLastName());
+ assertNull(person.getAge());
+}
+}}}
+
+Note if you want to limit objects to standard Java objects like List or Long you need
+[http://trac-hg.assembla.com/snakeyaml/browser/src/test/java/examples/SafeConstructorExampleTest.java to use SafeConstructor].
+{{{
+Loader loader = new Loader(new SafeConstructor());
+Yaml yaml = new Yaml(loader);
+}}}
+
+==== Providing the top level type ====
+
+It is possible to load a YAML document without any explicit tags. For instance, to load this document
+(example 2.27 from the [http://yaml.org/spec/1.1/#id859060 YAML specification])
+{{{
+invoice: 34843
+date : 2001-01-23
+billTo: &id001
+ given : Chris
+ family : Dumars
+ address:
+ lines: |
+ 458 Walkman Dr.
+ Suite #292
+ city : Royal Oak
+ state : MI
+ postal : 48046
+shipTo: *id001
+product:
+ - sku : BL394D
+ quantity : 4
+ description : Basketball
+ price : 450.00
+ - sku : BL4438H
+ quantity : 1
+ description : Super Hoop
+ price : 2392.00
+tax : 251.42
+total: 4443.52
+comments:
+ Late afternoon is best.
+ Backup contact is Nancy
+ Billsmer @ 338-4338.
+}}}
+into Invoice, Person, Address, Product instances the top level class in the object hierarchy
+[http://trac-hg.assembla.com/snakeyaml/browser/src/test/java/org/yaml/snakeyaml/Example2_27Test.java must be provided]:
+{{{
+Loader loader = new Loader(new Constructor(Invoice.class));
+Yaml yaml = new Yaml(loader);
+}}}
+SnakeYAML is using Reflection API to find out the class for all the properties (setters and public fields) on Invoice.
+Unfortunately because of erasure it is not possible to identify classes for type safe collections at runtime. The
+class information between <> is only available at compile time.
+
+=== Type safe collections ===
+
+In order to parse a collection which contains custom Java classes Yaml has to be provided with additional information.
+[http://trac-hg.assembla.com/snakeyaml/browser/src/main/java/org/yaml/snakeyaml/TypeDescription.java TypeDescription]
+serves the goal to collect more information and use it while loading/dumping.
+
+Let's say we have this document:
+{{{
+plate: 12-XP-F4
+wheels:
+- {id: 1}
+- {id: 2}
+- {id: 3}
+- {id: 4}
+- {id: 5}
+}}}
+and we would like to load this class
+{{{
+public class Car {
+ private String plate;
+ private List<Wheel> wheels;
+
+ public String getPlate() {
+ return plate;
+ }
+
+ public void setPlate(String plate) {
+ this.plate = plate;
+ }
+
+ public List<Wheel> getWheels() {
+ return wheels;
+ }
+
+ public void setWheels(List<Wheel> wheels) {
+ this.wheels = wheels;
+ }
+}
+}}}
+where 'wheels' property is a List of Wheel. In order to load Car (and create List<Wheel>)
+`TypeDescription` must be provided:
+{{{
+Constructor constructor = new Constructor(Car.class);//Car.class is root
+TypeDescription carDescription = new TypeDescription(Car.class);
+carDescription.putListPropertyType("wheels", Wheel.class);
+constructor.addTypeDefinition(carDescription);
+Loader loader = new Loader(constructor);
+Yaml yaml = new Yaml(loader);
+}}}
+The full example can be found
+[http://trac-hg.assembla.com/snakeyaml/browser/src/test/java/org/yaml/snakeyaml/constructor/TypeSafeCollectionsTest.java here]
+(testTypeSafeList()).
+
+A similar approach works for Maps. Please note that both keys and values of the Map can be of any type:
+{{{
+plate: 00-FF-Q2
+wheels:
+ ? {brand: Pirelli, id: 1}
+ : 2008-01-16
+ ? {brand: Dunkel, id: 2}
+ : 2002-12-24
+ ? {brand: Pirelli, id: 3}
+ : 2008-01-16
+ ? {brand: Pirelli, id: 4}
+ : 2008-01-16
+ ? {brand: Pirelli, id: 5}
+ : 2008-01-16
+}}}
+The class to be loaded:
+{{{
+public class MyCar {
+ private String plate;
+ private Map<MyWheel, Date> wheels;
+
+ public String getPlate() {
+ return plate;
+ }
+
+ public void setPlate(String plate) {
+ this.plate = plate;
+ }
+
+ public Map<MyWheel, Date> getWheels() {
+ return wheels;
+ }
+
+ public void setWheels(Map<MyWheel, Date> wheels) {
+ this.wheels = wheels;
+ }
+}
+}}}
+The [http://trac-hg.assembla.com/snakeyaml/browser/src/test/java/org/yaml/snakeyaml/constructor/TypeSafeCollectionsTest.java code]:
+{{{
+Constructor constructor = new Constructor(MyCar.class);
+TypeDescription carDescription = new TypeDescription(MyCar.class);
+carDescription.putMapPropertyType("wheels", MyWheel.class, Object.class);
+constructor.addTypeDefinition(carDescription);
+Loader loader = new Loader(constructor);
+Yaml yaml = new Yaml(loader);
+MyCar car = (MyCar) yaml.load(<see above>);
+}}}
+
+=== Dumping YAML ===
+
+The '''`Yaml.dump(Object data)`''' function accepts a Java object and produces a YAML document.
+(the source is [http://trac-hg.assembla.com/snakeyaml/browser/src/test/java/examples/DumpExampleTest.java here])
+{{{
+public void testDump() {
+ Map<String, Object> data = new HashMap<String, Object>();
+ data.put("name", "Silenthand Olleander");
+ data.put("race", "Human");
+ data.put("traits", new String[] { "ONE_HAND", "ONE_EYE" });
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(data);
+ System.out.println(output);
+}
+}}}
+{{{
+name: Silenthand Olleander
+traits: [ONE_HAND, ONE_EYE]
+race: Human
+}}}
+
+'''`Yaml.dump(Object data, Writer output)`''' will write the produced YAML document into
+the specified file/stream.
+
+{{{
+public void testDumpWriter() {
+ Map<String, Object> data = new HashMap<String, Object>();
+ data.put("name", "Silenthand Olleander");
+ data.put("race", "Human");
+ data.put("traits", new String[] { "ONE_HAND", "ONE_EYE" });
+ Yaml yaml = new Yaml();
+ StringWriter writer = new StringWriter();
+ yaml.dump(data, writer);
+ System.out.println(writer.toString());
+}
+}}}
+
+If you need to dump several YAML documents to a single stream, use the method
+'''`Yaml.dumpAll(Iterator<Object> data)`'''. It accepts an Iterator of
+Java objects to be serialized into a YAML document. A Writer can also be used.
+
+{{{
+public void testDumpMany() {
+ List<Integer> docs = new LinkedList<Integer>();
+ for (int i = 1; i < 4; i++) {
+ docs.add(i);
+ }
+ DumperOptions options = new DumperOptions();
+ options.explicitStart(true);
+ Yaml yaml = new Yaml(options);
+ System.out.println(yaml.dump(docs));
+ System.out.println(yaml.dumpAll(docs.iterator()));
+}
+}}}
+{{{
+--- [1, 2, 3]
+
+--- 1
+--- 2
+--- 3
+}}}
+
+You may even dump instances of `JavaBeans`.
+
+{{{
+public void testDumpCustomJavaClass() {
+ Hero hero = new Hero("Galain Ysseleg", -3, 2);
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(hero);
+ System.out.println(output);
+ assertEquals("!!examples.Hero {hp: -3, name: Galain Ysseleg, sp: 2}\n", output);
+}
+}}}
+{{{
+!!examples.Hero {hp: -3, name: Galain Ysseleg, sp: 2}
+}}}
+
+As you can see the `JavaBean` data is sorted althabetically.
+
+'''`DumperOptions`''' specifies
+formatting details for the emitter. For instance, you may set the
+preferred intendation and width, use the canonical YAML format or
+force preferred style for scalars and collections.
+{{{
+public void testDumperOptions() {
+ List<Integer> data = new LinkedList<Integer>();
+ for (int i = 0; i < 50; i++) {
+ data.add(i);
+ }
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(data);
+ System.out.println(output);
+ //
+ DumperOptions options = new DumperOptions();
+ options.setWidth(50);
+ options.setIndent(4);
+ yaml = new Yaml(options);
+ output = yaml.dump(data);
+ System.out.println(output);
+}
+}}}
+{{{
+[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
+ 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
+ 43, 44, 45, 46, 47, 48, 49]
+
+[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
+ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47, 48, 49]
+}}}
+Canonical output:
+{{{
+public void testDumperOptionsCanonical() {
+ List<Integer> data = new LinkedList<Integer>();
+ for (int i = 0; i < 5; i++) {
+ data.add(i);
+ }
+ DumperOptions options = new DumperOptions();
+ options.setCanonical(true);
+ Yaml yaml = new Yaml(options);
+ String output = yaml.dump(data);
+ System.out.println(output);
+}
+}}}
+{{{
+---
+!!seq [
+ !!int "0",
+ !!int "1",
+ !!int "2",
+ !!int "3",
+ !!int "4",
+]
+}}}
+{{{
+public void testDumperOptionsFlowStyle() {
+ List<Integer> data = new LinkedList<Integer>();
+ for (int i = 0; i < 5; i++) {
+ data.add(i);
+ }
+ DumperOptions options = new DumperOptions();
+ options.setDefaultFlowStyle(DumperOptions.DefaultFlowStyle.BLOCK);
+ Yaml yaml = new Yaml(options);
+ String output = yaml.dump(data);
+ System.out.println(output);
+}
+}}}
+{{{
+- 0
+- 1
+- 2
+- 3
+- 4
+}}}
+{{{
+public void testDumperOptionsStyle() {
+ List<Integer> data = new LinkedList<Integer>();
+ for (int i = 0; i < 5; i++) {
+ data.add(i);
+ }
+ DumperOptions options = new DumperOptions();
+ options.setDefaultStyle(DumperOptions.DefaultScalarStyle.DOUBLE_QUOTED);
+ Yaml yaml = new Yaml(options);
+ String output = yaml.dump(data);
+ System.out.println(output);
+}
+}}}
+{{{
+- !!int "0"
+- !!int "1"
+- !!int "2"
+- !!int "3"
+- !!int "4"
+}}}
+
+=== `JavaBeans` ===
+
+The spec says - "One of the main goals of the `JavaBeans` architecture is to provide a platform neutral component
+architecture."
+
+Avoiding global tags significantly improves ability to exchange the YAML documents between different
+platforms and languages.
+
+If the custom Java class conforms to the `JavaBean` specification it can be loaded and dumped
+without any extra code. For instance this `JavaBean`
+{{{
+public class CarWithWheel {
+ private String plate;
+ private String year;
+ private Wheel wheel;
+ private Object part;
+ private Map<String, Integer> map;
+
+ public String getPlate() {
+ return plate;
+ }
+
+ public void setPlate(String plate) {
+ this.plate = plate;
+ }
+
+ public Wheel getWheel() {
+ return wheel;
+ }
+
+ public void setWheel(Wheel wheel) {
+ this.wheel = wheel;
+ }
+
+ public Map<String, Integer> getMap() {
+ return map;
+ }
+
+ public void setMap(Map<String, Integer> map) {
+ this.map = map;
+ }
+
+ public Object getPart() {
+ return part;
+ }
+
+ public void setPart(Object part) {
+ this.part = part;
+ }
+
+ public String getYear() {
+ return year;
+ }
+
+ public void setYear(String year) {
+ this.year = year;
+ }
+}
+}}}
+{{{
+CarWithWheel car1 = new CarWithWheel();
+car1.setPlate("12-XP-F4");
+Wheel wheel = new Wheel();
+wheel.setId(2);
+car1.setWheel(wheel);
+Map<String, Integer> map = new HashMap<String, Integer>();
+map.put("id", 3);
+car1.setMap(map);
+car1.setPart(new Wheel(4));
+car1.setYear("2008");
+String output = new Yaml().dump(car1);
+}}}
+will be dumped as
+{{{
+!!package.CarWithWheel
+map: {id: 3}
+part: !!org.yaml.snakeyaml.constructor.Wheel {id: 4}
+plate: 12-XP-F4
+wheel: {id: 2}
+year: '2008'
+}}}
+Note that the 'part' property still has a global tag but the 'wheel' property does not
+(because the wheel's runtime class is the same as it is defined in the `CarWithWheel` class).
+
+The example for the above `JavaBean` can be found
+[http://trac-hg.assembla.com/snakeyaml/browser/src/test/java/org/yaml/snakeyaml/constructor/ImplicitTagsTest.java here]
+
+If it is nessesary to massage/skip the root global tag for the `JavaBean` it
+can be specified via `DumperOptions`.setExplicitRoot(String tag).
+
+There is a utility to parse `JavaBeans` - [http://trac-hg.assembla.com/snakeyaml/browser/src/main/java/org/yaml/snakeyaml/JavaBeanParser.java JavaBeanParser].
+All the methods of this utility are stateless and can be called from different Threads. The utility eliminates
+the need to cast returned instances to the specified class.
+
+=== Shortcuts ===
+
+There is a way to define local tags for custom classes.
+{{{
+!!org.yaml.snakeyaml.constructor.Car
+plate: 12-XP-F4
+wheels:
+- !!org.yaml.snakeyaml.constructor.Wheel {id: 1}
+- !!org.yaml.snakeyaml.constructor.Wheel {id: 2}
+- !!org.yaml.snakeyaml.constructor.Wheel {id: 3}
+- !!org.yaml.snakeyaml.constructor.Wheel {id: 4}
+- !!org.yaml.snakeyaml.constructor.Wheel {id: 5}
+}}}
+To eliminate long names while dumping Yaml
+[http://trac-hg.assembla.com/snakeyaml/browser/src/test/java/org/yaml/snakeyaml/constructor/ClassTagsTest.java should be configured]
+to use shortcuts:
+{{{
+Representer representer = new Representer();
+representer.putClassTag(Car.class, "!car");
+representer.putClassTag(Wheel.class, "tag:yaml.org,2002:map");
+Dumper dumper = new Dumper(representer, new DumperOptions());
+Yaml yaml = new Yaml(dumper);
+String output = yaml.dump(car);
+}}}
+This is the resulting output:
+{{{
+!car
+plate: 12-XP-F4
+wheels:
+- {id: 1}
+- {id: 2}
+- {id: 3}
+- {id: 4}
+- {id: 5}
+}}}
+Loader can be configured in a similar way:
+{{{
+Constructor constructor = new Constructor();
+constructor.putClassTag("!car", Car.class);
+Loader loader = new Loader(constructor);
+Yaml yaml = new Yaml(loader);
+}}}
+
+=== Constructors, representers, resolvers ===
+
+You may define your own application-specific tags. (the example's source is
+[http://trac-hg.assembla.com/snakeyaml/browser/src/test/java/examples/DiceExampleTest.java here])
+
+For instance, you may want to add a constructor
+and a representer for the following [http://trac-hg.assembla.com/snakeyaml/browser/src/test/java/examples/Dice.java Dice] class:
+{{{
+public class Dice {
+ private Integer a;
+ private Integer b;
+
+ public Dice(Integer a, Integer b) {
+ super();
+ this.a = a;
+ this.b = b;
+ }
+
+ public Integer getA() {
+ return a;
+ }
+
+ public Integer getB() {
+ return b;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof Dice) {
+ return toString().equals(obj.toString());
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return toString().hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return "Dice " + a + "d" + b;
+ }
+}
+}}}
+
+
+The default representation for '''`Dice`''' objects is not nice:
+{{{
+public void testRepresenter() throws IOException {
+ Dice dice = new Dice(3, 6);
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(dice);
+ System.out.println(output);
+}
+}}}
+{{{
+!!examples.Dice {a: 3, b: 6}
+}}}
+
+Suppose you want a '''`Dice`''' object to represented as '''`AdB`''' in YAML:
+{{{
+System.out.println(yaml.dump(new Dice(3,6)));
+
+3d6
+}}}
+
+First we define a representer that convert a dice object to scalar node
+with the tag `!dice` and register it.
+{{{
+class DiceRepresenter extends Representer {
+ public DiceRepresenter() {
+ this.representers.put(Dice.class, new RepresentDice());
+ }
+
+ private class RepresentDice implements Represent {
+ public Node representData(Object data) {
+ Dice dice = (Dice) data;
+ String value = dice.getA() + "d" + dice.getB();
+ return representScalar("!dice", value);
+ }
+ }
+}
+}}}
+
+Now you may dump an instance of the `Dice` object:
+{{{
+public void testDiceRepresenter() throws IOException {
+ Dice dice = new Dice(3, 6);
+ Map<String, Dice> data = new HashMap<String, Dice>();
+ data.put("gold", dice);
+ Yaml yaml = new Yaml(new Dumper(new DiceRepresenter(), new DumperOptions()));
+ String output = yaml.dump(data);
+ System.out.println(output);
+}
+}}}
+{{{
+{gold: !dice '10d6'}
+}}}
+
+Let us add the code to construct a Dice object:
+{{{
+class DiceConstructor extends Constructor {
+ public DiceConstructor() {
+ this.yamlConstructors.put("!dice", new ConstructDice());
+ }
+
+ private class ConstructDice implements Construct {
+ public Object construct(Node node) {
+ String val = (String) constructScalar(node);
+ int position = val.indexOf('d');
+ Integer a = Integer.parseInt(val.substring(0, position));
+ Integer b = Integer.parseInt(val.substring(position + 1));
+ return new Dice(a, b);
+ }
+ }
+}
+}}}
+
+Then you may load a `Dice` object as well:
+{{{
+public void testConstructor() throws IOException {
+ Yaml yaml = new Yaml(new Loader(new DiceConstructor()));
+ Object data = yaml.load("{initial hit points: !dice '8d4'}");
+ Map<String, Dice> map = (Map<String, Dice>) data;
+ assertEquals(new Dice(8, 4), map.get("initial hit points"));
+}
+}}}
+
+You might want to not specify the tag `!dice` everywhere. There is a way
+to teach SankeYAML that any untagged plain scalar that looks like XdY has
+the implicit tag `!dice`. Use '''`Yaml.addImplicitResolver(String tag, Pattern regexp, String first)`'''
+then you don't have to specify the tag to define a `Dice` object::
+{{{
+public void testImplicitResolver() throws IOException {
+ Yaml yaml = new Yaml(new Loader(new DiceConstructor()), new Dumper(new DiceRepresenter(),
+ new DumperOptions()));
+ yaml.addImplicitResolver("!dice", Pattern.compile("\\d+d\\d+"), "123456789");
+ // dump
+ Map<String, Dice> treasure = (Map<String, Dice>) new HashMap<String, Dice>();
+ treasure.put("treasure", new Dice(10, 20));
+ String output = yaml.dump(treasure);
+ System.out.println(output);
+ assertEquals("{treasure: 10d20}\n", output);
+ // load
+ Object data = yaml.load("{damage: 5d10}");
+ Map<String, Dice> map = (Map<String, Dice>) data;
+ assertEquals(new Dice(5, 10), map.get("damage"));
+}
+}}}
+{{{
+{treasure: 10d20}
+}}}
+
+== Enum ==
+SnakeYAML treats `Enum`s in a special way. (an example can be found
+[http://trac-hg.assembla.com/snakeyaml/browser/src/test/java/org/yaml/snakeyaml/EnumTest.java here])
+
+Normally an `Enum` requires an explicit global tag:
+{{{
+public void testDumpEnum() {
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(Suit.CLUBS);
+ assertEquals("!!org.yaml.snakeyaml.Suit 'CLUBS'\n", output);
+}
+
+public void testLoadEnum() {
+ Yaml yaml = new Yaml();
+ Suit suit = (Suit) yaml.load("!!org.yaml.snakeyaml.Suit 'CLUBS'");
+ assertEquals(Suit.CLUBS, suit);
+}
+}}}
+
+But if the Enum is a `JavaBean` property (and the class is implicitly defined) then the tags are not used:
+{{{
+public void testDumpEnumBean() {
+ DumperOptions options = new DumperOptions();
+ options.setDefaultFlowStyle(DumperOptions.DefaultFlowStyle.BLOCK);
+ Yaml yaml = new Yaml(options);
+ EnumBean bean = new EnumBean();
+ bean.setId(17);
+ bean.setSuit(Suit.SPADES);
+ String output = yaml.dump(bean);
+ System.out.println(output);
+}
+}}}
+{{{
+!!org.yaml.snakeyaml.EnumBean
+id: 17
+suit: SPADES
+}}}
+
+The same for loading:
+{{{
+public void testLoadEnumBean() {
+ Yaml yaml = new Yaml();
+ EnumBean bean = (EnumBean) yaml.load("!!org.yaml.snakeyaml.EnumBean\nid: 174\nsuit: CLUBS");
+ assertEquals(Suit.CLUBS, bean.getSuit());
+ assertEquals(174, bean.getId());
+}
+}}}
+
+== Threading ==
+
+Threads must have separate Yaml instances. Instances are cheap both in terms of time to create
+and memory to occupy. Only the very first instance is heavy because of static initializers for
+constants and regular expressions.
+
+Because Loader and Dumper are stateful they cannot be shared between
+different Yaml instances.
+
+== Spring ==
+
+Example of [http://trac-hg.assembla.com/snakeyaml/browser/src/test/resources/examples/spring.xml Spring definition]:
+(note: the scope is always 'prototype')
+{{{
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:util="http://www.springframework.org/schema/util" xmlns:p="http://www.springframework.org/schema/p"
+ xsi:schemaLocation="
+http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
+http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.0.xsd">
+
+ <!-- the most powerful way -->
+ <bean id="yamlConstructor" class="examples.CustomConstructor" scope="prototype" />
+ <bean id="yamlLoader" class="org.yaml.snakeyaml.Loader" scope="prototype">
+ <constructor-arg ref="yamlConstructor" />
+ </bean>
+ <bean id="yamlRepresenter" class="org.yaml.snakeyaml.representer.Representer" scope="prototype" />
+ <bean id="yamlOptions" class="org.yaml.snakeyaml.DumperOptions" scope="prototype">
+ <property name="indent" value="2" />
+ </bean>
+ <bean id="yamlDumper" class="org.yaml.snakeyaml.Dumper" scope="prototype">
+ <constructor-arg ref="yamlRepresenter" />
+ <constructor-arg ref="yamlOptions" />
+ </bean>
+ <bean id="snakeYaml" class="org.yaml.snakeyaml.Yaml" scope="prototype">
+ <constructor-arg ref="yamlLoader" />
+ <constructor-arg ref="yamlDumper" />
+ </bean>
+
+ <!-- for a single JavaBean -->
+ <bean id="beanConstructor" class="org.yaml.snakeyaml.constructor.Constructor" scope="prototype">
+ <constructor-arg value="org.yaml.snakeyaml.Invoice" />
+ </bean>
+ <bean id="beanLoader" class="org.yaml.snakeyaml.Loader" scope="prototype">
+ <constructor-arg ref="beanConstructor" />
+ </bean>
+ <bean id="javabeanYaml" class="org.yaml.snakeyaml.Yaml" scope="prototype">
+ <constructor-arg ref="beanLoader" />
+ </bean>
+
+ <!-- the simplest way -->
+ <bean id="standardYaml" class="org.yaml.snakeyaml.Yaml" scope="prototype" />
+</beans>
+}}}
+
+== Deviation from PyYAML ==
+
+ * SnakeYAML does not emit '...' (end of document) for simple documents
+ * SnakeYAML emits Unicode (not ASCII) by default
+
+== YAML syntax ==
+
+A good introduction to the YAML syntax is
+[http://yaml.org/spec/cvs/current.html#id857168 Chapter 2 of the YAML specification].
+
+You may also check [http://yaml4r.sourceforge.net/cookbook/ the YAML cookbook]. Note
+that it is focused on a Ruby implementation and uses the old YAML 1.0 syntax.
+
+Here we present most common YAML constructs together with the corresponding Java objects.
+
+
+=== Documents ===
+
+YAML stream is a collection of zero or more documents. An empty stream contains no documents.
+Documents are separated with '''`---`'''. Documents may optionally end with '''`...`'''.
+A single document may or may not be marked with '''`---`'''.
+
+Example of an implicit document:
+{{{
+- Multimedia
+- Internet
+- Education
+}}}
+
+Example of an explicit document:
+{{{
+---
+- Afterstep
+- CTWM
+- Oroborus
+...
+}}}
+
+Example of several documents in the same stream:
+{{{
+---
+- Ada
+- APL
+- ASP
+
+- Assembly
+- Awk
+---
+- Basic
+---
+- C
+- C# # Note that comments are denoted with ' #' (space and #).
+- C++
+- Cold Fusion
+}}}
+
+
+=== Block sequences ===
+
+In the block context, sequence entries are denoted by '''`- `''' (dash and space):
+{{{
+# YAML
+- The Dagger 'Narthanc'
+- The Dagger 'Nimthanc'
+- The Dagger 'Dethanc'
+}}}
+{{{
+# Java
+["The Dagger 'Narthanc'", "The Dagger 'Nimthanc'", "The Dagger 'Dethanc'"]
+}}}
+
+Block sequences can be nested:
+{{{
+# YAML
+-
+ - HTML
+ - LaTeX
+ - SGML
+ - VRML
+ - XML
+ - YAML
+-
+ - BSD
+ - GNU Hurd
+ - Linux
+}}}
+{{{
+# Java
+[['HTML', 'LaTeX', 'SGML', 'VRML', 'XML', 'YAML'], ['BSD', 'GNU Hurd', 'Linux']]
+}}}
+
+It's not necessary to start a nested sequence with a new line:
+{{{
+# YAML
+- 1.1
+- - 2.1
+ - 2.2
+- - - 3.1
+ - 3.2
+ - 3.3
+}}}
+{{{
+# Java
+[1.1, [2.1, 2.2], [[3.1, 3.2, 3.3]]]
+}}}
+
+A block sequence may be nested to a block mapping. Note that in this
+case it is not necessary to indent the sequence.
+{{{
+# YAML
+left hand:
+- Ring of Teleportation
+- Ring of Speed
+
+right hand:
+- Ring of Resist Fire
+- Ring of Resist Cold
+- Ring of Resist Poison
+}}}
+{{{
+# Java
+{'right hand': ['Ring of Resist Fire', 'Ring of Resist Cold', 'Ring of Resist Poison'],
+'left hand': ['Ring of Teleportation', 'Ring of Speed']}
+}}}
+
+
+=== Block mappings ===
+
+In the block context, keys and values of mappings are separated by '''`: `''' (colon and space):
+{{{
+# YAML
+base armor class: 0
+base damage: [4,4]
+plus to-hit: 12
+plus to-dam: 16
+plus to-ac: 0
+}}}
+{{{
+# Java
+{'plus to-hit': 12, 'base damage': [4, 4], 'base armor class': 0, 'plus to-ac': 0, 'plus to-dam': 16}
+}}}
+
+Complex keys are denoted with '''`? `''' (question mark and space):
+{{{
+# YAML
+? !!python/tuple [0,0]
+: The Hero
+? !!python/tuple [0,1]
+: Treasure
+? !!python/tuple [1,0]
+: Treasure
+? !!python/tuple [1,1]
+: The Dragon
+}}}
+{{{
+# Java
+{(0, 1): 'Treasure', (1, 0): 'Treasure', (0, 0): 'The Hero', (1, 1): 'The Dragon'}
+}}}
+
+Block mapping can be nested:
+{{{
+# YAML
+hero:
+ hp: 34
+ sp: 8
+ level: 4
+orc:
+ hp: 12
+ sp: 0
+ level: 2
+}}}
+{{{
+# Java
+{'hero': {'hp': 34, 'sp': 8, 'level': 4}, 'orc': {'hp': 12, 'sp': 0, 'level': 2}}
+}}}
+
+A block mapping may be nested in a block sequence:
+{{{
+# YAML
+- name: PyYAML
+ status: 4
+ license: MIT
+ language: Python
+- name: PySyck
+ status: 5
+ license: BSD
+ language: Python
+}}}
+{{{
+# Java
+[{'status': 4, 'language': 'Python', 'name': 'PyYAML', 'license': 'MIT'},
+{'status': 5, 'license': 'BSD', 'name': 'PySyck', 'language': 'Python'}]
+}}}
+
+
+=== Flow collections ===
+
+The syntax of flow collections in YAML is very close to the syntax of list and
+dictionary constructors in Python:
+{{{
+# YAML
+{ str: [15, 17], con: [16, 16], dex: [17, 18], wis: [16, 16], int: [10, 13], chr: [5, 8] }
+}}}
+{{{
+# Java
+{'dex': [17, 18], 'int': [10, 13], 'chr': [5, 8], 'wis': [16, 16], 'str': [15, 17], 'con': [16, 16]}
+}}}
+
+
+=== Scalars ===
+
+There are 5 styles of scalars in YAML: plain, single-quoted, double-quoted, literal, and folded:
+{{{
+# YAML
+plain: Scroll of Remove Curse
+single-quoted: 'EASY_KNOW'
+double-quoted: "?"
+literal: | # Borrowed from http://www.kersbergen.com/flump/religion.html
+ by hjw ___
+ __ /.-.\
+ / )_____________\\ Y
+ /_ /=== == === === =\ _\_
+ ( /)=== == === === == Y \
+ `-------------------( o )
+ \___/
+folded: >
+ It removes all ordinary curses from all equipped items.
+ Heavy or permanent curses are unaffected.
+}}}
+{{{
+# Java
+{'plain': 'Scroll of Remove Curse',
+'literal':
+ 'by hjw ___\n'
+ ' __ /.-.\\\n'
+ ' / )_____________\\\\ Y\n'
+ ' /_ /=== == === === =\\ _\\_\n'
+ '( /)=== == === === == Y \\\n'
+ ' `-------------------( o )\n'
+ ' \\___/\n',
+'single-quoted': 'EASY_KNOW',
+'double-quoted': '?',
+'folded': 'It removes all ordinary curses from all equipped items. Heavy or permanent curses are unaffected.\n'}
+}}}
+
+Each style has its own quirks. A plain scalar does not use indicators to denote its
+start and end, therefore it's the most restricted style. Its natural applications are
+names of attributes and parameters.
+
+Using single-quoted scalars, you may express any value that does not contain special characters.
+No escaping occurs for single quoted scalars except that duplicate quotes '''`''`''' are replaced
+with a single quote '''`'`'''.
+
+Double-quoted is the most powerful style and the only style that can express any scalar value.
+Double-quoted scalars allow ''escaping''. Using escaping sequences '''`\x**`''' and '''`\u****`''',
+you may express any ASCII or Unicode character.
+
+There are two kind of block scalar styles: '''literal''' and '''folded'''. The literal style is
+the most suitable style for large block of text such as source code. The folded style is similar
+to the literal style, but two consequent non-empty lines are joined to a single line separated
+by a space character.
+
+
+=== Aliases ===
+
+Using YAML you may represent objects of arbitrary graph-like structures. If you want to refer
+to the same object from different parts of a document, you need to use anchors and aliases.
+
+Anchors are denoted by the '''`&`''' indicator while aliases are denoted by '''`*`'''. For instance,
+the document
+{{{
+left hand: &A
+ name: The Bastard Sword of Eowyn
+ weight: 30
+right hand: *A
+}}}
+expresses the idea of a hero holding a heavy sword in both hands.
+
+SnakeYAML now fully supports recursive objects. For instance, the document
+{{{
+&A [ *A ]
+}}}
+will produce a list object containing a reference to itself.
+
+
+=== Tags ===
+
+Tags are used to denote the type of a YAML node. Standard YAML tags are defined at
+http://yaml.org/type/index.html.
+
+Tags may be implicit:
+{{{
+boolean: true
+integer: 3
+float: 3.14
+}}}
+{{{
+#!python
+{'boolean': True, 'integer': 3, 'float': 3.14}
+}}}
+
+or explicit:
+{{{
+boolean: !!bool "true"
+integer: !!int "3"
+float: !!float "3.14"
+}}}
+{{{
+#!python
+{'boolean': True, 'integer': 3, 'float': 3.14}
+}}}
+
+Plain scalars without explicitly defined tag are subject to implicit tag
+resolution. The scalar value is checked against a set of regular expressions
+and if one of them matches, the corresponding tag is assigned to the scalar.
+SnakeYAML allows an application to add custom implicit tag resolvers.
+
+
+== YAML tags and Java types ==
+
+The following table describes how nodes with different tags are converted
+to Java objects.
+
+|| '''YAML tag''' || '''Java type''' ||
+|| ''Standard YAML tags'' || ||
+|| `!!null` || `null` ||
+|| `!!bool` || `Boolean` ||
+|| `!!int` || `Integer, Long, BigInteger` ||
+|| `!!float` || `Double` ||
+|| `!!binary` || `String` ||
+|| `!!timestamp` || `java.util.Date`, `java.sql.Date` ||
+|| `!!omap`, `!!pairs` || `List` of `Object[]` ||
+|| `!!set` || `Set` ||
+|| `!!str` || `String` ||
+|| `!!seq` || `List` ||
+|| `!!map` || `Map` ||
+
+An example of loading and dumping [http://yaml.org/spec/1.1/#id858961 Global tags] can be found
+[http://trac-hg.assembla.com/snakeyaml/browser/src/test/java/org/yaml/snakeyaml/Example2_24Test.java here].
+
+== Collections ==
+
+Default implementations of collections are:
+ * ''List'': `LinkedList`
+ * ''Map'': `LinkedHashMap` (the order is implicitly defined)
+
+It is possible to define other default implementations. An example can be found
+[http://trac-hg.assembla.com/snakeyaml/browser/src/test/java/examples/CustomListExampleTest.java here] for List and
+[http://trac-hg.assembla.com/snakeyaml/browser/src/test/java/examples/CustomMapExampleTest.java here] for Map
+
+== Deviations from the specification ==
+
+''need to update this section''
+
+ * rules for tabs in YAML are confusing. We are close, but not there yet.
+ Perhaps both the spec and the parser should be fixed. Anyway, the best
+ rule for tabs in YAML is to not use them at all.
+ * Byte order mark. The initial BOM is stripped, but BOMs inside the stream
+ are considered as parts of the content. It can be fixed, but it's not
+ really important now.
+ * ~~Empty plain scalars are not allowed if alias or tag is specified.~~ This
+ is done to prevent anomalities like '''[ !tag, value]''', which can be
+ interpreted both as '''[ !<!tag,> value ]''' and '''[ !<!tag> "", "value" ]'''.
+ The spec should be fixed.
+ * Indentation of flow collections. The spec requires them to be indented
+ more than their block parent node. Unfortunately this rule renders many intuitively
+ correct constructs invalid, for instance,
+{{{
+block: {
+} # this is indentation violation according to the spec.
+}}}
+ * ':' is not allowed for plain scalars in the flow mode. ~~~'''{1:2}''' is
+ interpreted as '''{ 1 : 2 }'''.~~~
+
+
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 00000000..1071f536
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,163 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>SnakeYAML</groupId>
+ <artifactId>SnakeYAML</artifactId>
+ <version>1.1</version>
+ <packaging>jar</packaging>
+ <name>SnakeYAML</name>
+ <description>YAML 1.1 parser and emitter for Java</description>
+ <inceptionYear>2008</inceptionYear>
+ <url>http://trac-hg.assembla.com/snakeyaml/</url>
+ <issueManagement>
+ <system>Trac</system>
+ <url>http://trac-hg.assembla.com/snakeyaml/report</url>
+ </issueManagement>
+ <mailingLists>
+ <mailingList>
+ <name>SnakeYAML developers and users List</name>
+ <post>snakeyaml-core@googlegroups.com</post>
+ </mailingList>
+ </mailingLists>
+ <scm>
+ <connection>scm:hg:http://hg.assembla.com/snakeyaml</connection>
+ <url>http://trac-hg.assembla.com/snakeyaml/browser</url>
+ </scm>
+ <licenses>
+ <license>
+ <name>The MIT License</name>
+ <url>LICENSE</url>
+ </license>
+ </licenses>
+ <developers>
+ <developer>
+ <id>py4fun</id>
+ <name>Andrey Somov</name>
+ <email>py4fun@gmail.com</email>
+ </developer>
+ </developers>
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>3.8.2</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring</artifactId>
+ <version>2.5.6</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.5</source>
+ <target>1.5</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <includes>
+ <include>**/*Test.java</include>
+ </includes>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-eclipse-plugin</artifactId>
+ <configuration>
+ <buildOutputDirectory>bin</buildOutputDirectory>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>cobertura-maven-plugin</artifactId>
+ <version>2.2</version>
+ <configuration>
+ <check>
+ <totalBranchRate>80</totalBranchRate>
+ <totalLineRate>95</totalLineRate>
+ </check>
+ <formats>
+ <format>html</format>
+ <format>xml</format>
+ </formats>
+ </configuration>
+ <executions>
+ <execution>
+ <goals>
+ <goal>clean</goal>
+ <goal>check</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ <reporting>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-changes-plugin</artifactId>
+ <reportSets>
+ <reportSet>
+ <reports>
+ <report>changes-report</report>
+ </reports>
+ </reportSet>
+ </reportSets>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-report-plugin</artifactId>
+ <configuration>
+ <showSuccess>true</showSuccess>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>cobertura-maven-plugin</artifactId>
+ <configuration>
+ <formats>
+ <format>html</format>
+ <format>xml</format>
+ </formats>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>jxr-maven-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <reportSets>
+ <reportSet>
+ <id>html</id>
+ <configuration>
+ <doctitle>API for ${project.name} ${project.version}</doctitle>
+ <windowtitle>API for ${project.name} ${project.version}</windowtitle>
+ <testDoctitle>Test API for ${project.name} ${project.version}</testDoctitle>
+ <testWindowtitle>Test API for ${project.name} ${project.version}</testWindowtitle>
+ </configuration>
+ <reports>
+ <report>javadoc</report>
+ </reports>
+ </reportSet>
+ </reportSets>
+ </plugin>
+ </plugins>
+ </reporting>
+ <distributionManagement>
+ <repository>
+ <id>internal</id>
+ <name>SnakeYAML Repo</name>
+ <url>http://10.3.3.26:8080/archiva/repository/internal</url>
+ </repository>
+ </distributionManagement>
+</project>
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
new file mode 100644
index 00000000..8b4f7d18
--- /dev/null
+++ b/src/changes/changes.xml
@@ -0,0 +1,458 @@
+<document>
+ <properties>
+ <title>YAML 1.1 parser and emitter</title>
+ <author email="py4fun@gmail.com">Andrey Somov</author>
+ </properties>
+ <body>
+ <release version="1.1" date="2009-03-14" description="improve performance and test coverage">
+ <action dev="py4fun" type="add">
+ Introduce JavaBeanParser (2009-03-14)
+ </action>
+ <action dev="py4fun" type="add">
+ Introduce DumperOptions.Version enum (2009-03-13)
+ </action>
+ <action dev="py4fun" type="add">
+ Introduce DumperOptions.LineBreak enum (2009-03-10)
+ </action>
+ <action dev="py4fun" type="update">
+ Use byte[] for binary type. (2009-03-09)
+ </action>
+ <action dev="py4fun" type="update">
+ Restore Regular Expressions in Resolver. Ragel gives only 5% performance increase.
+ Fix a bug in Resolver with expanded regular expressions which caused the
+ performance problem. (2009-03-06)
+ </action>
+ <action dev="py4fun" type="add">
+ Better Spring support: it is now possible to create a constructor with a String
+ as the class name. (2009-03-05)
+ </action>
+ <action dev="py4fun" type="update">
+ Throw an exception when the same Loader or Dumper instance is shared between
+ different Yaml instances. Because they are statefull it is not Thread-safe. (2009-03-05)
+ </action>
+ <action dev="py4fun" type="add">
+ Add possibility to set a meaningful name for Yaml instance to be shown in toString(). (2009-03-05)
+ </action>
+ <action dev="py4fun" type="update">
+ Refactor: declare classes which are not expected to be extended as final. (2009-03-04)
+ </action>
+ <action dev="py4fun" type="update">
+ Refactor: use 'final' keyword to identify immutable fields. (2009-03-04)
+ </action>
+ <action dev="py4fun" type="update">
+ Refactor: do not use 'final' keyword for local variables. (2009-03-04)
+ </action>
+ <action dev="py4fun" type="fix">
+ Fix: respect implicit resolvers with 'null' as a first character. (2009-03-02)
+ </action>
+ <action dev="py4fun" type="update">
+ Refactor: use Character instead of String as a key for implicit resolvers. (2009-03-02)
+ </action>
+ <action dev="py4fun" type="add">
+ Use Ragel instead of Regular Expressions for implicit types. (2009-03-02)
+ </action>
+ <action dev="py4fun" type="fix">
+ Fix ticket #4: java.sql.Date not handled. Thanks to Christophe Desguez (2009-02-28)
+ </action>
+ <action dev="py4fun" type="add">
+ Introduce DumperOptions.DefaultFlowStyle enum (2009-02-24)
+ </action>
+ <action dev="py4fun" type="add">
+ Introduce DumperOptions.DefaultScalarStyle enum (2009-02-24)
+ </action>
+ <action dev="py4fun" type="update">
+ Refactor: use 'switch' with Enum instead of multiple 'if' statements to distinguish nodes (2009-02-19)
+ </action>
+ <action dev="py4fun" type="update">
+ Refactor: use Enum instead of String as NodeId (2009-02-19)
+ </action>
+ </release>
+ <release version="1.0.1" date="2009-02-18" description="implement Enum support">
+ <action dev="py4fun" type="fix">
+ Do not emit anchors for Enum (2009-02-18)
+ </action>
+ <action dev="py4fun" type="fix">
+ Enum as a JavaBean property (when the Enum class is implicitly defined) does
+ not need tags for both loading and dumping (2009-02-17)
+ </action>
+ <action dev="py4fun" type="fix">
+ Enum is emitted as a scalar node (2009-02-17)
+ </action>
+ <action dev="py4fun" type="fix">
+ Enum is parsed as a scalar node or as a JavaBean property (2009-02-17)
+ </action>
+ <action dev="py4fun" type="update">
+ Refactor: for performance ScannerImpl.stalePossibleSimpleKeys() does not copy key Set (2009-02-10)
+ </action>
+ <action dev="py4fun" type="update">
+ By default allowUnicode=true. If it is necessary to escape Unicode use
+ DumperOptions.setAllowUnicode(false) (2009-02-09)
+ </action>
+ <action dev="py4fun" type="add">
+ Implement allowUnicode setting (to escape Unicode characters on non UTF-8 terminals) (2009-02-09)
+ </action>
+ <action dev="py4fun" type="add">
+ Add possibility to specify tags for dumping (2009-02-09)
+ </action>
+ <action dev="py4fun" type="update">
+ Rename getExpRoot to getExplicitRoot to conform with
+ standard JavaBean naming convention (2009-02-09)
+ </action>
+ <action dev="py4fun" type="update">
+ Rename explictStart and explicitEnd to standard setters to conform with
+ standard JavaBean naming convention (2009-02-09)
+ </action>
+ <action dev="py4fun" type="fix">
+ Add possibility to specify a line break (2009-02-09)
+ </action>
+ </release>
+ <release version="1.0" date="2009-02-06" description="final 1.0 release">
+ <action dev="py4fun" type="fix">
+ Use LinkedHashMap for Emitter.tagPrefixes to respect the order (2009-02-06)
+ </action>
+ <action dev="py4fun" type="fix">
+ Use LinkedHashMap for ScannerImpl.possibleSimpleKeys to respect the key order (2009-02-05)
+ </action>
+ <action dev="py4fun" type="add">
+ Add a test to prove that Yaml instances are independent and can safely be used in
+ multithreaded environment like for instance a Servlet container (2009-02-05)
+ </action>
+ <action dev="py4fun" type="update">
+ The mailing list is renamed to snakeyaml-core to avoid a
+ name conflict in Google AppEngine (2009-02-03)
+ </action>
+ </release>
+ <release version="1.0rc2" date="2008-01-22" description="Improve JavaBeans support">
+ <action dev="py4fun" type="add">
+ Provide possibility to define/eliminate the root tag for JavaBeans. Avoiding global tags
+ helps to exchange YAML documents with other programming languages (2009-01-21)
+ </action>
+ <action dev="py4fun" type="fix">
+ Arrays as JavaBens properties are properly supported (2009-01-21)
+ </action>
+ <action dev="py4fun" type="update">
+ Do not emit redundant tags for JavaBeans (2009-01-20)
+ </action>
+ <action dev="py4fun" type="add">
+ Respect public fields in JavaBeans (2009-01-20)
+ </action>
+ </release>
+ <release version="1.0rc1" date="2009-01-16" description="Construct type safe collections">
+ <action dev="py4fun" type="update">
+ Replace String.getBytes(Charset charset) with String.getBytes(String charsetName) because
+ String.getBytes(Charset charset) was introduced only in Java 6 (2009-01-16)
+ </action>
+ <action dev="py4fun" type="update">
+ Replace LinkedList.pop() with removeFirst() because pop() was
+ introduced only in Java 6 (2009-01-16)
+ </action>
+ <action dev="py4fun" type="update">
+ Replace LinkedList.push() with addFirst() because push() was
+ introduced only in Java 6 (2009-01-16)
+ </action>
+ <action dev="py4fun" type="add">
+ Implement type safe Map as a property of custom Java class (2009-01-16)
+ </action>
+ <action dev="py4fun" type="add">
+ Implement type safe List as a property of custom Java class (2009-01-15)
+ </action>
+ <action dev="py4fun" type="update">
+ Construct interface does not use generics. The type information is set
+ to the Node (2009-01-15)
+ </action>
+ <action dev="py4fun" type="add">
+ Introduce TypeDescription as a single configuration option for a custom class (2009-01-15)
+ </action>
+ </release>
+ <release version="0.91" date="2008-01-14" description="Support shortcut tags for custom classes">
+ <action dev="py4fun" type="add">
+ Add possibility to define shortcut tags for custom classes while loading (2009-01-13)
+ </action>
+ <action dev="py4fun" type="add">
+ Add possibility to define shortcut tags for custom classes while dumping (2009-01-13)
+ </action>
+ <action dev="py4fun" type="add">
+ Construct List as a JavaBean property. But due to erasure only standard Java
+ classes created (2009-01-13)
+ </action>
+ <action dev="py4fun" type="add">
+ Import PyStructureTest from PyYAML (2009-01-13)
+ </action>
+ <action dev="py4fun" type="add">
+ Import canonical scanner and parser from PyYAML (2009-01-12)
+ </action>
+ </release>
+ <release version="0.9" date="2008-01-12" description="Add possibility to define a root class for Loader">
+ <action dev="py4fun" type="add">
+ Finish 2.27 example from the specification (2009-01-12)
+ </action>
+ <action dev="py4fun" type="add">
+ Add possibility to define a root class for Loader (2009-01-11)
+ </action>
+ <action dev="py4fun" type="update">
+ Use Java Generics in the Construct interface (2009-01-11)
+ </action>
+ <action dev="py4fun" type="update">
+ Use Java Generics in the Scanner interface (2009-01-08)
+ </action>
+ <action dev="py4fun" type="update">
+ Create ScannerIml only in ParserImpl (2009-01-08)
+ </action>
+ <action dev="py4fun" type="fix">
+ Import changeset 312 from PyYAML. Fix a bug in Emitter when writing folded scalars (2009-01-07)
+ </action>
+ </release>
+ <release version="0.8" date="2009-01-07" description="Import changes from PyYAML 3.08">
+ <action dev="py4fun" type="add">
+ Add possibility to use java.io.Reader as input. BOM must be respected. (2009-01-06)
+ </action>
+ <action dev="py4fun" type="update">
+ Import Changeset 308 from PyYAML: Refactored whitespace combination
+ detector in the scalar analyser. (2009-01-06)
+ </action>
+ <action dev="py4fun" type="update">
+ Import Changeset 313 from PyYAML: Emit an explicit document end indicator
+ when there is a possibility of ambiguous parsing. (2009-01-06)
+ </action>
+ <action dev="py4fun" type="update">
+ Use global tags (with !!) to dump Java custom instances. (2009-01-05)
+ </action>
+ <action dev="py4fun" type="update">
+ Use global tags (with !!) to load Java custom instances. (2009-01-05)
+ </action>
+ <action dev="py4fun" type="add">
+ Add example of defining a custom List and Map implementations. (2009-01-04)
+ </action>
+ <action dev="py4fun" type="fix">
+ Fix parsing Long.MIN_VALUE: respect the sign when parsing integers. (2009-01-04)
+ </action>
+ <action dev="py4fun" type="update">
+ when constructing integers try to create the first in the following order:
+ Integer -> Long -> BigInteger. (2009-01-02)
+ </action>
+ </release>
+ <release version="0.7" date="2008-12-20" description="Improve test coverage">
+ <action dev="py4fun" type="update">
+ Improve test coverage for constructor package (2008-12-20)
+ </action>
+ <action dev="py4fun" type="remove">
+ Remove support for "value" type because it is not used (2008-12-20)
+ </action>
+ <action dev="py4fun" type="update">
+ Require test coverage 95% (2008-12-19)
+ </action>
+ <action dev="py4fun" type="update">
+ Improve test coverage for Nodes (2008-12-19)
+ </action>
+ <action dev="py4fun" type="fix">
+ Fix dumping Date and better coverage for Representer (2008-12-19)
+ </action>
+ <action dev="py4fun" type="remove">
+ Remove unused code based on coverage report (2008-12-19)
+ </action>
+ <action dev="py4fun" type="remove">
+ Tokens are 100% covered by tests (2008-12-19)
+ </action>
+ <action dev="py4fun" type="remove">
+ Remove old tests (2008-12-18)
+ </action>
+ <action dev="py4fun" type="update">
+ Synchronized with PyYAML revision 307
+ </action>
+ </release>
+ <release version="0.6" date="2008-12-17" description="Documentation added">
+ <action dev="py4fun" type="add">
+ Many examples added to the Wiki page (2008-12-17)
+ </action>
+ <action dev="py4fun" type="update">
+ Public interface is using Iterator instead of Iterable (2008-12-17)
+ </action>
+ <action dev="py4fun" type="update">
+ Sort names when JavaBeans are represented (2008-12-15)
+ </action>
+ <action dev="py4fun" type="fix">
+ defaultFlowStyle for Dumper is configurable in DumperOptions (2008-12-12)
+ </action>
+ </release>
+ <release version="0.5" date="2008-12-12" description="Import PyYAML 3.06">
+ <action dev="py4fun" type="add">
+ Add possibility to define an implicit resolver. {359:63190d5bcd10} (2008-12-11)
+ </action>
+ <action dev="py4fun" type="add">
+ Add possibility to define an explicit constructor. {356:ccaa0df9ca98} (2008-12-11)
+ </action>
+ <action dev="py4fun" type="update">
+ Java objects can be constructed from mapping (JavaBeans), from sequence (constructor)
+ from scalar (constructor). (2008-12-10)
+ </action>
+ <action dev="py4fun" type="fix">
+ pairs tag works properly. (2008-12-08)
+ </action>
+ <action dev="py4fun" type="fix">
+ omap tag works properly. (2008-12-08)
+ </action>
+ <action dev="py4fun" type="add">
+ Implement possibility to define a custom Map implementation {332}. (2008-12-06)
+ </action>
+ <action dev="py4fun" type="add">
+ Implement possibility to define a custom List implementation {331:72c03254c184}. (2008-12-06)
+ </action>
+ <action dev="py4fun" type="add">
+ Path resolver is removed because it is not imported properly {330}. (2008-12-06)
+ </action>
+ <action dev="py4fun" type="add">
+ Constructor is overwritten completely. (2008-12-06)
+ </action>
+ <action dev="py4fun" type="add">
+ Implement possibility to define a custom Representer. (2008-12-01)
+ </action>
+ <action dev="py4fun" type="update">
+ Support arrays of reference types. Arrays of primitives are not supported
+ because Arrays.asList() does not work. (2008-12-01)
+ </action>
+ <action dev="py4fun" type="update">
+ Import change 300 for Emitter from PyYAML. (2008-12-01)
+ </action>
+ <action dev="py4fun" type="fix">
+ Fix Node identity to avoid aliases for simple types - [1, 1]. (2008-11-28)
+ </action>
+ <action dev="py4fun" type="update">
+ Recursive objects can be represented (but not yet constructed) (2008-11-28)
+ </action>
+ <action dev="py4fun" type="update">
+ Binary is represented back as String (2008-11-28)
+ </action>
+ <action dev="py4fun" type="update">
+ Re-write Representer classes from scratch (2008-11-28)
+ </action>
+ <action dev="py4fun" type="fix">
+ 'null' can be a key in a map (2008-11-21)
+ </action>
+ <action dev="py4fun" type="fix">
+ !!set tag is parsed properly (2008-11-21)
+ </action>
+ <action dev="py4fun" type="update">
+ Single characters 'Y', 'N', 'y' and 'n' are parsed as String opposed to boolean
+ as it is defined in the specification. This is how it is done in PyYAML (2008-11-21)
+ </action>
+ <action dev="py4fun" type="remove">
+ Constructor: because Java does not have generators 'deep' is not
+ imported from PyYAML (2008-11-19)
+ </action>
+ <action dev="py4fun" type="update">
+ Composer imported from PyYAML (2008-11-17)
+ </action>
+ <action dev="py4fun" type="update">
+ Resolver.resolve() is using simple boolean argument instead of array of booleans
+ as in PyYAML. (2008-11-18)
+ </action>
+ <action dev="py4fun" type="fix">
+ Fix: 'set' type works. (2008-11-18)
+ </action>
+ <action dev="py4fun" type="update">
+ Rewrite Parser from scratch. (2008-11-17)
+ </action>
+ </release>
+ <release version="0.4" date="2008-11-11" description="Fix issues in Scanner">
+ <action dev="py4fun" type="update">
+ Move constants from Yaml interface to appropriate classes (2008-11-10)
+ </action>
+ <action dev="py4fun" type="update">
+ Interface change: Yaml dumpAll() methods accept Iterable (2008-11-10)
+ </action>
+ <action dev="py4fun" type="update">
+ Interface change: Yaml loadAll() methods return Iterable (2008-11-10)
+ </action>
+ <action dev="py4fun" type="fix">
+ Scanner: copy keys to avoid java.util.ConcurrentModificationException when removing
+ possible simple key (2008-11-10)
+ </action>
+ <action dev="py4fun" type="update">
+ Tag v0.3.1 (2008-11-08)
+ </action>
+ <action dev="py4fun" type="update">
+ MappingNode requires Map as a value and SequenceNode requires
+ List as a value (2008-11-08)
+ </action>
+ <action dev="py4fun" type="update">
+ Marks in a Token are required (2008-11-08)
+ </action>
+ <action dev="py4fun" type="remove">
+ Remove prefixForward() method from Reader because it is not present
+ in PyYAML (2008-11-08)
+ </action>
+ <action dev="py4fun" type="fix">
+ Fix a deviation with PyYAML in method scanBlockScalar().
+ 'chomping' can be null. Fix a bug in JvYaml that the trailing '\n' in a
+ block scalar was removed.(2008-11-07)
+ </action>
+ <action dev="py4fun" type="fix">
+ Fix a deviation with PyYAML in method scanDirectiveIgnoredLine().
+ Put '#' instead of '"'. (2008-11-07)
+ </action>
+ <action dev="py4fun" type="add">
+ Restore from PyYAML the way the keys are parsed. (Restored methods are
+ stalePossibleSimpleKeys() and removePossibleSimpleKey().)
+ Fix issue http://code.google.com/p/jvyamlb/issues/detail?id=6. (2008-11-07)
+ </action>
+ <action dev="py4fun" type="update">
+ Refactor: put changed classes to 'org.yaml.snakeyaml' package. (2008-11-05)
+ </action>
+ <action dev="py4fun" type="update">
+ Move all the main() methods to the corresponding test classes. (2008-11-05)
+ </action>
+ <action dev="py4fun" type="update">
+ Change public interface. Rename YAML to Yaml. Remove all static methods from Yaml.
+ Factory and configuration must be injected at the constructor. This way is closer
+ to PyYAML API. (2008-11-05)
+ </action>
+ <action dev="py4fun" type="add">
+ Reader as in PyYAML is implemented. BOM is properly supported (2008-11-05)
+ </action>
+ <action dev="py4fun" type="add">
+ Restore Mark in Token as it is in PyYAML. Mark is not defined yet (2008-10-30)
+ </action>
+ <action dev="py4fun" type="fix">
+ Off-by-one in EmitterImpl.writeDoubleQuoted().
+ Fix issue: https://jvyaml.dev.java.net/issues/show_bug.cgi?id=11 (2008-10-28)
+ </action>
+ <action dev="py4fun" type="fix">
+ Respect Unicode characters.
+ Fix issue: https://jvyaml.dev.java.net/issues/show_bug.cgi?id=10 (2008-10-28)
+ </action>
+ <action dev="py4fun" type="fix">
+ Respect sign for float.
+ Fix issue: https://jvyaml.dev.java.net/issues/show_bug.cgi?id=13 (2008-10-28)
+ </action>
+ <action dev="py4fun" type="add">
+ Binary data is represented as ByteBuffer (2008-10-27)
+ </action>
+ <action dev="py4fun" type="fix">
+ When parsed, a timestamp in the canonical form (i.e, 2001-12-15T02:59:43.1Z) is
+ interpreted as if it is in the default time zone.
+ Fix issue: https://jvyaml.dev.java.net/issues/show_bug.cgi?id=7 (2008-10-27)
+ </action>
+ <action dev="py4fun" type="add">
+ Add Mark from PyYAML. It is not used yet. The JUnit test is migrated from PyYAML (2008-10-23)
+ </action>
+ <action dev="py4fun" type="update">
+ Apply SnakeYAML as the name of the library (2008-10-22)
+ </action>
+ <action dev="py4fun" type="update">
+ Reformat the source files (2008-10-22)
+ </action>
+ <action dev="py4fun" type="update">
+ Apply LICENSE info to source files (2008-10-22)
+ </action>
+ <action dev="py4fun" type="update">
+ Mavenize project. Apply standard Maven folder structure (2008-10-20)
+ </action>
+ </release>
+ <release version="0.2.1" date="2008-10-20" description="Import JvYaml from CVS">
+ <action dev="py4fun" type="add">
+ Import project from https://jvyaml.dev.java.net/ (2008-10-20)
+ </action>
+ </release>
+ </body>
+</document>
+
diff --git a/src/main/java/org/yaml/snakeyaml/Dumper.java b/src/main/java/org/yaml/snakeyaml/Dumper.java
new file mode 100644
index 00000000..763ba731
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/Dumper.java
@@ -0,0 +1,56 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml;
+
+import java.io.Writer;
+import java.util.Iterator;
+
+import org.yaml.snakeyaml.emitter.Emitter;
+import org.yaml.snakeyaml.error.YAMLException;
+import org.yaml.snakeyaml.representer.Representer;
+import org.yaml.snakeyaml.resolver.Resolver;
+import org.yaml.snakeyaml.serializer.Serializer;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public class Dumper {
+ private final Representer representer;
+ private final DumperOptions options;
+ private boolean attached = false;
+
+ public Dumper(Representer representer, DumperOptions options) {
+ this.representer = representer;
+ this.options = options;
+ }
+
+ public Dumper(DumperOptions options) {
+ this(new Representer(options.getDefaultStyle().getChar(), options.getDefaultFlowStyle()
+ .getStyleBoolean()), options);
+ }
+
+ public void dump(Iterator<? extends Object> iter, Writer output, Resolver resolver) {
+ Serializer s = new Serializer(new Emitter(output, options), resolver, options);
+ try {
+ s.open();
+ while (iter.hasNext()) {
+ representer.represent(s, iter.next());
+ }
+ s.close();
+ } catch (java.io.IOException e) {
+ throw new YAMLException(e);
+ }
+ }
+
+ /**
+ * Because Dumper is stateful it cannot be shared
+ */
+ void setAttached() {
+ if (!attached) {
+ attached = true;
+ } else {
+ throw new YAMLException("Dumper cannot be shared.");
+ }
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/DumperOptions.java b/src/main/java/org/yaml/snakeyaml/DumperOptions.java
new file mode 100644
index 00000000..49e69ae5
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/DumperOptions.java
@@ -0,0 +1,251 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml;
+
+import java.util.Map;
+
+import org.yaml.snakeyaml.emitter.Emitter;
+import org.yaml.snakeyaml.error.YAMLException;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public class DumperOptions {
+ public enum DefaultScalarStyle {
+ DOUBLE_QUOTED(new Character('"')), SINGLE_QUOTED(new Character('\'')), LITERAL(
+ new Character('|')), FOLDED(new Character('>')), PLAIN(null);
+ private Character styleChar;
+
+ private DefaultScalarStyle(Character defaultStyle) {
+ this.styleChar = defaultStyle;
+ }
+
+ public Character getChar() {
+ return styleChar;
+ }
+
+ @Override
+ public String toString() {
+ return "Scalar style: '" + styleChar + "'";
+ }
+ }
+
+ public enum DefaultFlowStyle {
+ FLOW(Boolean.TRUE), BLOCK(Boolean.FALSE), AUTO(null);
+
+ private Boolean styleBoolean;
+
+ private DefaultFlowStyle(Boolean defaultFlowStyle) {
+ styleBoolean = defaultFlowStyle;
+ }
+
+ public Boolean getStyleBoolean() {
+ return styleBoolean;
+ }
+
+ @Override
+ public String toString() {
+ return "Flow style: '" + styleBoolean + "'";
+ }
+ }
+
+ public enum LineBreak {
+ WIN("\r\n"), MAC("\r"), LINUX("\n");
+
+ private String lineBreak;
+
+ private LineBreak(String lineBreak) {
+ this.lineBreak = lineBreak;
+ }
+
+ public String getString() {
+ return lineBreak;
+ }
+
+ @Override
+ public String toString() {
+ return "Line break: " + name();
+ }
+ }
+
+ public enum Version {
+ V1_0(new Integer[] { 1, 0 }), V1_1(new Integer[] { 1, 1 });
+
+ private Integer[] version;
+
+ private Version(Integer[] version) {
+ this.version = version;
+ }
+
+ public Integer[] getArray() {
+ return version;
+ }
+
+ @Override
+ public String toString() {
+ return "Version: " + version[0] + "." + version[1];
+ }
+ }
+
+ private DefaultScalarStyle defaultStyle = DefaultScalarStyle.PLAIN;
+ private DefaultFlowStyle defaultFlowStyle = DefaultFlowStyle.AUTO;
+ private boolean canonical = false;
+ private boolean allowUnicode = true;
+ private int indent = 2;
+ private int bestWidth = 80;
+ private LineBreak lineBreak = LineBreak.LINUX;
+ private boolean explicitStart = false;
+ private boolean explicitEnd = false;
+ private String explicitRoot = null;
+ private Version version = null;
+ private Map<String, String> tags = null;
+
+ public boolean isAllowUnicode() {
+ return allowUnicode;
+ }
+
+ /**
+ * Specify whether to emit non-ASCII printable Unicode characters (to
+ * support ASCII terminals). The default value is true.
+ *
+ * @param allowUnicode
+ * - if allowUnicode is false then all non-ASCII characters are
+ * escaped
+ */
+ public void setAllowUnicode(boolean allowUnicode) {
+ this.allowUnicode = allowUnicode;
+ }
+
+ public DefaultScalarStyle getDefaultStyle() {
+ return defaultStyle;
+ }
+
+ /**
+ * Set default style for scalars. See YAML 1.1 specification, 2.3 Scalars
+ * (http://yaml.org/spec/1.1/#id858081)
+ *
+ * @param defaultStyle
+ */
+ public void setDefaultStyle(DefaultScalarStyle defaultStyle) {
+ if (defaultStyle == null) {
+ throw new NullPointerException("Use DefaultScalarStyle enum.");
+ }
+ this.defaultStyle = defaultStyle;
+ }
+
+ public void setIndent(int indent) {
+ if (indent < Emitter.MIN_INDENT) {
+ throw new YAMLException("Indent must be at least " + Emitter.MIN_INDENT);
+ }
+ if (indent > Emitter.MAX_INDENT) {
+ throw new YAMLException("Indent must be at most " + Emitter.MAX_INDENT);
+ }
+ this.indent = indent;
+ }
+
+ public int getIndent() {
+ return this.indent;
+ }
+
+ public void setVersion(Version version) {
+ this.version = version;
+ }
+
+ public Version getVersion() {
+ return this.version;
+ }
+
+ public DumperOptions setCanonical(boolean canonical) {
+ this.canonical = canonical;
+ return this;
+ }
+
+ public boolean isCanonical() {
+ return this.canonical;
+ }
+
+ /**
+ * Specify the preferred width to emit scalars. When the scalar
+ * representation takes more then the preferred with the scalar will be
+ * split into a few lines. The default is 80.
+ *
+ * @param bestWidth
+ * - the preferred with for scalars.
+ */
+ public void setWidth(int bestWidth) {
+ this.bestWidth = bestWidth;
+ }
+
+ public int getWidth() {
+ return this.bestWidth;
+ }
+
+ public LineBreak getLineBreak() {
+ return lineBreak;
+ }
+
+ public void setDefaultFlowStyle(DefaultFlowStyle defaultFlowStyle) {
+ if (defaultFlowStyle == null) {
+ throw new NullPointerException("Use DefaultFlowStyle enum.");
+ }
+ this.defaultFlowStyle = defaultFlowStyle;
+ }
+
+ public DefaultFlowStyle getDefaultFlowStyle() {
+ return defaultFlowStyle;
+ }
+
+ public String getExplicitRoot() {
+ return explicitRoot;
+ }
+
+ /**
+ * @param expRoot
+ * - tag to be used for the root node or <code>null</code> to get
+ * the default
+ */
+ public void setExplicitRoot(String expRoot) {
+ if (expRoot == null) {
+ throw new NullPointerException("Root tag must be specified.");
+ }
+ this.explicitRoot = expRoot;
+ }
+
+ /**
+ * Specify the line break to separate the lines. It is platform specific:
+ * Windows - "\r\n", MacOS - "\r", Linux - "\n". The default value is the
+ * one for Linux.
+ */
+ public void setLineBreak(LineBreak lineBreak) {
+ if (lineBreak == null) {
+ throw new NullPointerException("Specify line break.");
+ }
+ this.lineBreak = lineBreak;
+ }
+
+ public boolean isExplicitStart() {
+ return explicitStart;
+ }
+
+ public void setExplicitStart(boolean explicitStart) {
+ this.explicitStart = explicitStart;
+ }
+
+ public boolean isExplicitEnd() {
+ return explicitEnd;
+ }
+
+ public void setExplicitEnd(boolean explicitEnd) {
+ this.explicitEnd = explicitEnd;
+ }
+
+ public Map<String, String> getTags() {
+ return tags;
+ }
+
+ public void setTags(Map<String, String> tags) {
+ this.tags = tags;
+ }
+
+}
diff --git a/src/main/java/org/yaml/snakeyaml/JavaBeanParser.java b/src/main/java/org/yaml/snakeyaml/JavaBeanParser.java
new file mode 100644
index 00000000..4495bf1f
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/JavaBeanParser.java
@@ -0,0 +1,75 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml;
+
+import java.io.InputStream;
+import java.io.StringReader;
+
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.reader.UnicodeReader;
+import org.yaml.snakeyaml.resolver.Resolver;
+
+/**
+ * Convenience utility to parse JavaBeans. The returned instance is enforced to
+ * be of the same class as the provided argument. All the methods are Thread
+ * safe. When the YAML document contains a global tag with the class definition
+ * like '!!com.package.MyBean' it is ignored in favour of the runtime class.
+ */
+public class JavaBeanParser {
+
+ private JavaBeanParser() {
+ }
+
+ /**
+ * @param yaml
+ * - YAML document
+ * @param javabean
+ * - JavaBean class to be parsed
+ * @return parsed JavaBean
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> T load(String yaml, Class<T> javabean) {
+ Loader loader = createLoader(javabean);
+ return (T) loader.load(new StringReader(yaml));
+ }
+
+ /**
+ * Parse the first YAML document in a stream and produce the corresponding
+ * JavaBean.
+ *
+ * @param io
+ * - data to load from (BOM is respected and removed)
+ * @param javabean
+ * - JavaBean class to be parsed
+ * @return parsed JavaBean
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> T load(InputStream io, Class<T> javabean) {
+ Loader loader = createLoader(javabean);
+ return (T) loader.load(new UnicodeReader(io));
+ }
+
+ /**
+ * Parse the first YAML document in a stream and produce the corresponding
+ * Java object.
+ *
+ * @param io
+ * - data to load from (BOM must not be present)
+ * @param javabean
+ * - JavaBean class to be parsed
+ * @return parsed JavaBean
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> T load(java.io.Reader io, Class<T> javabean) {
+ Loader loader = createLoader(javabean);
+ return (T) loader.load(io);
+ }
+
+ private static Loader createLoader(Class<? extends Object> clazz) {
+ Loader loader = new Loader(new Constructor(clazz));
+ Resolver resolver = new Resolver();
+ loader.setResolver(resolver);
+ return loader;
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/Loader.java b/src/main/java/org/yaml/snakeyaml/Loader.java
new file mode 100644
index 00000000..ffdc5eb5
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/Loader.java
@@ -0,0 +1,86 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml;
+
+import java.util.Iterator;
+
+import org.yaml.snakeyaml.composer.Composer;
+import org.yaml.snakeyaml.constructor.BaseConstructor;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.error.YAMLException;
+import org.yaml.snakeyaml.parser.ParserImpl;
+import org.yaml.snakeyaml.reader.Reader;
+import org.yaml.snakeyaml.resolver.Resolver;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public class Loader {
+ protected final BaseConstructor constructor;
+ protected Resolver resolver;
+ private boolean attached = false;
+
+ public Loader(BaseConstructor constructor) {
+ super();
+ this.constructor = constructor;
+ this.resolver = new Resolver();
+ }
+
+ public Loader() {
+ this(new Constructor());
+ }
+
+ public Object load(java.io.Reader io) {
+ Composer composer = new Composer(new ParserImpl(new Reader(io)), resolver);
+ constructor.setComposer(composer);
+ return constructor.getSingleData();
+ }
+
+ public Iterable<Object> loadAll(java.io.Reader yaml) {
+ Composer composer = new Composer(new ParserImpl(new Reader(yaml)), resolver);
+ this.constructor.setComposer(composer);
+ Iterator<Object> result = new Iterator<Object>() {
+ public boolean hasNext() {
+ return constructor.checkData();
+ }
+
+ public Object next() {
+ return constructor.getData();
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ return new YamlIterable(result);
+ }
+
+ private class YamlIterable implements Iterable<Object> {
+ private Iterator<Object> iterator;
+
+ public YamlIterable(Iterator<Object> iterator) {
+ this.iterator = iterator;
+ }
+
+ public Iterator<Object> iterator() {
+ return iterator;
+ }
+
+ }
+
+ public void setResolver(Resolver resolver) {
+ this.resolver = resolver;
+ }
+
+ /**
+ * Because Loader is stateful it cannot be shared
+ */
+ void setAttached() {
+ if (!attached) {
+ attached = true;
+ } else {
+ throw new YAMLException("Loader cannot be shared.");
+ }
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/TypeDescription.java b/src/main/java/org/yaml/snakeyaml/TypeDescription.java
new file mode 100644
index 00000000..27eb1dcf
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/TypeDescription.java
@@ -0,0 +1,145 @@
+package org.yaml.snakeyaml;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Provides additional runtime information necessary to create a custom Java
+ * instance.
+ */
+public final class TypeDescription {
+ private final Class<? extends Object> type;
+ private String tag;
+ private boolean root;
+ private Map<String, Class<? extends Object>> listProperties;
+ private Map<String, Class<? extends Object>> keyProperties;
+ private Map<String, Class<? extends Object>> valueProperties;
+
+ public TypeDescription(Class<? extends Object> clazz, String tag) {
+ this.type = clazz;
+ this.tag = tag;
+ listProperties = new HashMap<String, Class<? extends Object>>();
+ keyProperties = new HashMap<String, Class<? extends Object>>();
+ valueProperties = new HashMap<String, Class<? extends Object>>();
+ }
+
+ public TypeDescription(Class<? extends Object> clazz) {
+ this(clazz, null);
+ }
+
+ /**
+ * Get tag which shall be used to load or dump the type (class).
+ *
+ * @return tag to be used. It may be a tag for Language-Independent Types
+ * (http://www.yaml.org/type/)
+ */
+ public String getTag() {
+ return tag;
+ }
+
+ /**
+ * Set tag to be used to load or dump the type (class).
+ *
+ * @param tag
+ * - local or global tag
+ */
+ public void setTag(String tag) {
+ this.tag = tag;
+ }
+
+ /**
+ * Get represented type (class)
+ *
+ * @return type (class) to be described.
+ */
+ public Class<? extends Object> getType() {
+ return type;
+ }
+
+ /**
+ * Defines whether this type (class) is the root of the YAML document
+ *
+ * @return true if this type shall be used as a root of object hierarchy.
+ */
+ public boolean isRoot() {
+ return root;
+ }
+
+ /**
+ * Specify whether this type (class) should be serve as the root of the YAML
+ * document
+ *
+ * @param root
+ * - true if this type shall be used as a root of object
+ * hierarchy.
+ */
+ public void setRoot(boolean root) {
+ this.root = root;
+ }
+
+ /**
+ * Specify that the property is a type-safe <code>List</code>.
+ *
+ * @param property
+ * - name of the JavaBean property
+ * @param type
+ * - class of List values
+ */
+ public void putListPropertyType(String property, Class<? extends Object> type) {
+ listProperties.put(property, type);
+ }
+
+ /**
+ * Get class of List values for provided JavaBean property.
+ *
+ * @param property
+ * - property name
+ * @return class of List values
+ */
+ public Class<? extends Object> getListPropertyType(String property) {
+ return listProperties.get(property);
+ }
+
+ /**
+ * Specify that the property is a type-safe <code>Map</code>.
+ *
+ * @param property
+ * - property name of this JavaBean
+ * @param key
+ * - class of keys in Map
+ * @param value
+ * - class of values in Map
+ */
+ public void putMapPropertyType(String property, Class<? extends Object> key,
+ Class<? extends Object> value) {
+ keyProperties.put(property, key);
+ valueProperties.put(property, value);
+ }
+
+ /**
+ * Get keys type info for this JavaBean
+ *
+ * @param property
+ * - property name of this JavaBean
+ * @return class of keys in the Map
+ */
+ public Class<? extends Object> getMapKeyType(String property) {
+ return keyProperties.get(property);
+ }
+
+ /**
+ * Get values type info for this JavaBean
+ *
+ * @param property
+ * - property name of this JavaBean
+ * @return class of values in the Map
+ */
+ public Class<? extends Object> getMapValueType(String property) {
+ return valueProperties.get(property);
+ }
+
+ @Override
+ public String toString() {
+ return "TypeDescription for " + getType() + " (tag='" + getTag() + "')";
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/Yaml.java b/src/main/java/org/yaml/snakeyaml/Yaml.java
new file mode 100644
index 00000000..f99a286d
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/Yaml.java
@@ -0,0 +1,223 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml;
+
+import java.io.InputStream;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import org.yaml.snakeyaml.reader.UnicodeReader;
+import org.yaml.snakeyaml.resolver.Resolver;
+
+/**
+ * Public YAML interface. Each Thread must have its own instance.
+ */
+public class Yaml {
+ private final Dumper dumper;
+ private final Loader loader;
+ private final Resolver resolver;
+ private String name;
+
+ public Yaml(DumperOptions options) {
+ this(new Loader(), new Dumper(options));
+ }
+
+ public Yaml(Dumper dumper) {
+ this(new Loader(), dumper);
+ }
+
+ public Yaml(Loader loader) {
+ this(loader, new Dumper(new DumperOptions()));
+ }
+
+ /**
+ * Create Yaml instance. It is safe to create a few instances and use them
+ * in different Threads.
+ *
+ * @param loader
+ * - Loader to parse incoming documents
+ * @param dumper
+ * - Dumper to emit outgoing objects
+ */
+ public Yaml(Loader loader, Dumper dumper) {
+ this.loader = loader;
+ loader.setAttached();
+ this.dumper = dumper;
+ dumper.setAttached();
+ this.resolver = new Resolver();
+ this.loader.setResolver(resolver);
+ this.name = "Yaml:" + System.identityHashCode(this);
+ }
+
+ public Yaml() {
+ this(new Loader(), new Dumper(new DumperOptions()));
+ }
+
+ /**
+ * Serialize a Java object into a YAML String.
+ *
+ * @param data
+ * - Java object to be Serialized to YAML
+ * @return YAML String
+ */
+ public String dump(Object data) {
+ List<Object> lst = new ArrayList<Object>(1);
+ lst.add(data);
+ return dumpAll(lst.iterator());
+ }
+
+ /**
+ * Serialize a sequence of Java objects into a YAML String.
+ *
+ * @param data
+ * - Iterator with Objects
+ * @return - YAML String with all the objects in proper sequence
+ */
+ public String dumpAll(Iterator<? extends Object> data) {
+ StringWriter buffer = new StringWriter();
+ dumpAll(data, buffer);
+ return buffer.toString();
+ }
+
+ /**
+ * Serialize a Java object into a YAML stream.
+ *
+ * @param data
+ * - Java object to be Serialized to YAML
+ * @param output
+ * - stream to write to
+ */
+ public void dump(Object data, Writer output) {
+ List<Object> lst = new ArrayList<Object>(1);
+ lst.add(data);
+ dumpAll(lst.iterator(), output);
+ }
+
+ /**
+ * Serialize a sequence of Java objects into a YAML stream.
+ *
+ * @param data
+ * - Iterator with Objects
+ * @param output
+ * - stream to write to
+ */
+ public void dumpAll(Iterator<? extends Object> data, Writer output) {
+ dumper.dump(data, output, resolver);
+ }
+
+ /**
+ * Parse the first YAML document in a String and produce the corresponding
+ * Java object. (Because the encoding in known BOM is not respected.)
+ *
+ * @param yaml
+ * - YAML data to load from (BOM must not be present)
+ * @return parsed object
+ */
+ public Object load(String yaml) {
+ return loader.load(new StringReader(yaml));
+ }
+
+ /**
+ * Parse the first YAML document in a stream and produce the corresponding
+ * Java object.
+ *
+ * @param io
+ * - data to load from (BOM is respected and removed)
+ * @return parsed object
+ */
+ public Object load(InputStream io) {
+ return loader.load(new UnicodeReader(io));
+ }
+
+ /**
+ * Parse the first YAML document in a stream and produce the corresponding
+ * Java object.
+ *
+ * @param io
+ * - data to load from (BOM must not be present)
+ * @return parsed object
+ */
+ public Object load(java.io.Reader io) {
+ return loader.load(io);
+ }
+
+ /**
+ * Parse all YAML documents in a String and produce corresponding Java
+ * objects.
+ *
+ * @param yaml
+ * - YAML data to load from (BOM must not be present)
+ * @return an iterator over the parsed Java objects in this String in proper
+ * sequence
+ */
+ public Iterable<Object> loadAll(java.io.Reader yaml) {
+ return loader.loadAll(yaml);
+ }
+
+ /**
+ * Parse all YAML documents in a String and produce corresponding Java
+ * objects. (Because the encoding in known BOM is not respected.)
+ *
+ * @param yaml
+ * - YAML data to load from (BOM must not be present)
+ * @return an iterator over the parsed Java objects in this String in proper
+ * sequence
+ */
+ public Iterable<Object> loadAll(String yaml) {
+ return loadAll(new StringReader(yaml));
+ }
+
+ /**
+ * Parse all YAML documents in a stream and produce corresponding Java
+ * objects.
+ *
+ * @param yaml
+ * - YAML data to load from (BOM is respected and ignored)
+ * @return an iterator over the parsed Java objects in this stream in proper
+ * sequence
+ */
+ public Iterable<Object> loadAll(InputStream yaml) {
+ return loadAll(new UnicodeReader(yaml));
+ }
+
+ /**
+ * Add an implicit scalar detector. If an implicit scalar value matches the
+ * given regexp, the corresponding tag is assigned to the scalar. first is a
+ * sequence of possible initial characters or null (which means any).
+ *
+ * @param tag
+ * - tag to assign to the node
+ * @param regexp
+ * - regular expression to match against
+ * @param first
+ * - a sequence of possible initial characters or None
+ */
+ public void addImplicitResolver(String tag, Pattern regexp, String first) {
+ resolver.addImplicitResolver(tag, regexp, first);
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Set a meaningful name to be shown in toString()
+ *
+ * @param name
+ * - human readable name
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/composer/Composer.java b/src/main/java/org/yaml/snakeyaml/composer/Composer.java
new file mode 100644
index 00000000..c95d5e0c
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/composer/Composer.java
@@ -0,0 +1,181 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.composer;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.yaml.snakeyaml.events.AliasEvent;
+import org.yaml.snakeyaml.events.Event;
+import org.yaml.snakeyaml.events.MappingEndEvent;
+import org.yaml.snakeyaml.events.MappingStartEvent;
+import org.yaml.snakeyaml.events.NodeEvent;
+import org.yaml.snakeyaml.events.ScalarEvent;
+import org.yaml.snakeyaml.events.SequenceEndEvent;
+import org.yaml.snakeyaml.events.SequenceStartEvent;
+import org.yaml.snakeyaml.events.StreamEndEvent;
+import org.yaml.snakeyaml.events.StreamStartEvent;
+import org.yaml.snakeyaml.nodes.CollectionNode;
+import org.yaml.snakeyaml.nodes.MappingNode;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.NodeId;
+import org.yaml.snakeyaml.nodes.ScalarNode;
+import org.yaml.snakeyaml.nodes.SequenceNode;
+import org.yaml.snakeyaml.parser.Parser;
+import org.yaml.snakeyaml.resolver.Resolver;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public class Composer {
+ private final Parser parser;
+ private final Resolver resolver;
+ private final Map<String, Node> anchors;
+
+ public Composer(Parser parser, Resolver resolver) {
+ this.parser = parser;
+ this.resolver = resolver;
+ this.anchors = new HashMap<String, Node>();
+ }
+
+ public boolean checkNode() {
+ // Drop the STREAM-START event.
+ if (parser.checkEvent(StreamStartEvent.class)) {
+ parser.getEvent();
+ }
+ // If there are more documents available?
+ return !parser.checkEvent(StreamEndEvent.class);
+ }
+
+ public Node getNode() {
+ // Get the root node of the next document.
+ if (!parser.checkEvent(StreamEndEvent.class)) {
+ return composeDocument();
+ } else {
+ return (Node) null;
+ }
+ }
+
+ public Node getSingleNode() {
+ // Drop the STREAM-START event.
+ parser.getEvent();
+ // Compose a document if the stream is not empty.
+ Node document = null;
+ if (!parser.checkEvent(StreamEndEvent.class)) {
+ document = composeDocument();
+ }
+ // Ensure that the stream contains no more documents.
+ if (!parser.checkEvent(StreamEndEvent.class)) {
+ Event event = parser.getEvent();
+ throw new ComposerException("expected a single document in the stream", document
+ .getStartMark(), "but found another document", event.getStartMark());
+ }
+ // Drop the STREAM-END event.
+ parser.getEvent();
+ return document;
+ }
+
+ private Node composeDocument() {
+ // Drop the DOCUMENT-START event.
+ parser.getEvent();
+ // Compose the root node.
+ Node node = composeNode(null, null);
+ // Drop the DOCUMENT-END event.
+ parser.getEvent();
+ this.anchors.clear();
+ return node;
+ }
+
+ private Node composeNode(Node parent, Object index) {
+ if (parser.checkEvent(AliasEvent.class)) {
+ AliasEvent event = (AliasEvent) parser.getEvent();
+ String anchor = event.getAnchor();
+ if (!anchors.containsKey(anchor)) {
+ throw new ComposerException(null, null, "found undefined alias " + anchor, event
+ .getStartMark());
+ }
+ return (Node) anchors.get(anchor);
+ }
+ NodeEvent event = (NodeEvent) parser.peekEvent();
+ String anchor = null;
+ anchor = event.getAnchor();
+ if (anchor != null) {
+ if (anchors.containsKey(anchor)) {
+ throw new ComposerException("found duplicate anchor " + anchor
+ + "; first occurence", this.anchors.get(anchor).getStartMark(),
+ "second occurence", event.getStartMark());
+ }
+ }
+ // resolver.descendResolver(parent, index);
+ Node node = null;
+ if (parser.checkEvent(ScalarEvent.class)) {
+ node = composeScalarNode(anchor);
+ } else if (parser.checkEvent(SequenceStartEvent.class)) {
+ node = composeSequenceNode(anchor);
+ } else {
+ node = composeMappingNode(anchor);
+ }
+ // resolver.ascendResolver();
+ return node;
+ }
+
+ private Node composeScalarNode(String anchor) {
+ ScalarEvent ev = (ScalarEvent) parser.getEvent();
+ String tag = ev.getTag();
+ if (tag == null || tag.equals("!")) {
+ tag = resolver.resolve(NodeId.scalar, ev.getValue(), ev.getImplicit()[0]);
+ }
+ Node node = new ScalarNode(tag, ev.getValue(), ev.getStartMark(), ev.getEndMark(), ev
+ .getStyle());
+ if (anchor != null) {
+ anchors.put(anchor, node);
+ }
+ return node;
+ }
+
+ @SuppressWarnings("unchecked")
+ private Node composeSequenceNode(String anchor) {
+ SequenceStartEvent startEvent = (SequenceStartEvent) parser.getEvent();
+ String tag = startEvent.getTag();
+ if (tag == null || tag.equals("!")) {
+ tag = resolver.resolve(NodeId.sequence, null, startEvent.getImplicit());
+ }
+ CollectionNode node = new SequenceNode(tag, new LinkedList<Node>(), startEvent
+ .getStartMark(), null, startEvent.getFlowStyle());
+ if (anchor != null) {
+ anchors.put(anchor, node);
+ }
+ int index = 0;
+ while (!parser.checkEvent(SequenceEndEvent.class)) {
+ ((List<Object>) node.getValue()).add(composeNode(node, new Integer(index)));
+ index++;
+ }
+ Event endEvent = parser.getEvent();
+ node.setEndMark(endEvent.getEndMark());
+ return node;
+ }
+
+ private Node composeMappingNode(String anchor) {
+ MappingStartEvent startEvent = (MappingStartEvent) parser.getEvent();
+ String tag = startEvent.getTag();
+ if (tag == null || tag.equals("!")) {
+ tag = resolver.resolve(NodeId.mapping, null, startEvent.getImplicit());
+ }
+ MappingNode node = new MappingNode(tag, new LinkedList<Node[]>(),
+ startEvent.getStartMark(), null, startEvent.getFlowStyle());
+ if (anchor != null) {
+ anchors.put(anchor, node);
+ }
+ while (!parser.checkEvent(MappingEndEvent.class)) {
+ Node itemKey = composeNode(node, null);
+ Node itemValue = composeNode(node, itemKey);
+ node.getValue().add(new Node[] { itemKey, itemValue });//
+ }
+ Event endEvent = parser.getEvent();
+ node.setEndMark(endEvent.getEndMark());
+ return node;
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/composer/ComposerException.java b/src/main/java/org/yaml/snakeyaml/composer/ComposerException.java
new file mode 100644
index 00000000..9fda8087
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/composer/ComposerException.java
@@ -0,0 +1,19 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.composer;
+
+import org.yaml.snakeyaml.error.Mark;
+import org.yaml.snakeyaml.error.MarkedYAMLException;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public class ComposerException extends MarkedYAMLException {
+ private static final long serialVersionUID = 2146314636913113935L;
+
+ protected ComposerException(String context, Mark contextMark, String problem, Mark problemMark) {
+ super(context, contextMark, problem, problemMark);
+ }
+
+}
diff --git a/src/main/java/org/yaml/snakeyaml/constructor/BaseConstructor.java b/src/main/java/org/yaml/snakeyaml/constructor/BaseConstructor.java
new file mode 100644
index 00000000..704c1f54
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/constructor/BaseConstructor.java
@@ -0,0 +1,152 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.constructor;
+
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.yaml.snakeyaml.composer.Composer;
+import org.yaml.snakeyaml.nodes.MappingNode;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.ScalarNode;
+import org.yaml.snakeyaml.nodes.SequenceNode;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public class BaseConstructor {
+ protected final Map<String, Construct> yamlConstructors = new HashMap<String, Construct>();
+
+ private Composer composer;
+ private final Map<Node, Object> constructedObjects;
+ private final Map<Node, Object> recursiveObjects;
+
+ protected Class<? extends Object> rootType;
+
+ public BaseConstructor() {
+ constructedObjects = new HashMap<Node, Object>();
+ recursiveObjects = new HashMap<Node, Object>();
+ rootType = Object.class;
+ }
+
+ public void setComposer(Composer composer) {
+ this.composer = composer;
+ }
+
+ public boolean checkData() {
+ // If there are more documents available?
+ return composer.checkNode();
+ }
+
+ public Object getData() {
+ // Construct and return the next document.
+ composer.checkNode();
+ Node node = composer.getNode();
+ node.setType(rootType);
+ return constructDocument(node);
+ }
+
+ public Object getSingleData() {
+ // Ensure that the stream contains a single document and construct it
+ Node node = composer.getSingleNode();
+ if (node != null) {
+ node.setType(rootType);
+ return constructDocument(node);
+ }
+ return null;
+ }
+
+ private Object constructDocument(Node node) {
+ Object data = constructObject(node);
+ constructedObjects.clear();
+ recursiveObjects.clear();
+ return data;
+ }
+
+ protected Object constructObject(Node node) {
+ if (constructedObjects.containsKey(node)) {
+ return constructedObjects.get(node);
+ }
+ if (recursiveObjects.containsKey(node)) {
+ throw new ConstructorException(null, null, "found unconstructable recursive node", node
+ .getStartMark());
+ }
+ recursiveObjects.put(node, null);
+ Object data = callConstructor(node);
+ constructedObjects.put(node, data);
+ recursiveObjects.remove(node);
+ return data;
+ }
+
+ protected Object callConstructor(Node node) {
+ Object data = null;
+ Construct constructor = null;
+ constructor = yamlConstructors.get(node.getTag());
+ if (constructor == null) {
+ constructor = yamlConstructors.get(null);
+ data = constructor.construct(node);
+ } else {
+ data = constructor.construct(node);
+ }
+ return data;
+ }
+
+ protected Object constructScalar(ScalarNode node) {
+ return node.getValue();
+ }
+
+ protected List<Object> createDefaultList(int initSize) {
+ return new LinkedList<Object>();
+ }
+
+ protected List<? extends Object> constructSequence(SequenceNode node) {
+ List<Node> nodeValue = (List<Node>) node.getValue();
+ List<Object> result = createDefaultList(nodeValue.size());
+ for (Node child : nodeValue) {
+ result.add(constructObject(child));
+ }
+ return result;
+ }
+
+ protected Map<Object, Object> createDefaultMap() {
+ // respect order from YAML document
+ return new LinkedHashMap<Object, Object>();
+ }
+
+ protected Map<Object, Object> constructMapping(MappingNode node) {
+ Map<Object, Object> mapping = createDefaultMap();
+ List<Node[]> nodeValue = (List<Node[]>) node.getValue();
+ for (Node[] tuple : nodeValue) {
+ Node keyNode = tuple[0];
+ Node valueNode = tuple[1];
+ Object key = constructObject(keyNode);
+ if (key != null) {
+ try {
+ key.hashCode();// check circular dependencies
+ } catch (Exception e) {
+ throw new ConstructorException("while constructing a mapping", node
+ .getStartMark(), "found unacceptable key " + key, tuple[0]
+ .getStartMark());
+ }
+ }
+ Object value = constructObject(valueNode);
+ mapping.put(key, value);
+ }
+ return mapping;
+ }
+ // TODO protected List<Object[]> constructPairs(MappingNode node) {
+ // List<Object[]> pairs = new LinkedList<Object[]>();
+ // List<Node[]> nodeValue = (List<Node[]>) node.getValue();
+ // for (Iterator<Node[]> iter = nodeValue.iterator(); iter.hasNext();) {
+ // Node[] tuple = iter.next();
+ // Object key = constructObject(Object.class, tuple[0]);
+ // Object value = constructObject(Object.class, tuple[1]);
+ // pairs.add(new Object[] { key, value });
+ // }
+ // return pairs;
+ // }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/constructor/Construct.java b/src/main/java/org/yaml/snakeyaml/constructor/Construct.java
new file mode 100644
index 00000000..55e27b06
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/constructor/Construct.java
@@ -0,0 +1,10 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.constructor;
+
+import org.yaml.snakeyaml.nodes.Node;
+
+public interface Construct {
+ public Object construct(Node node);
+}
diff --git a/src/main/java/org/yaml/snakeyaml/constructor/Constructor.java b/src/main/java/org/yaml/snakeyaml/constructor/Constructor.java
new file mode 100644
index 00000000..1a0b3242
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/constructor/Constructor.java
@@ -0,0 +1,348 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.constructor;
+
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.math.BigInteger;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.yaml.snakeyaml.TypeDescription;
+import org.yaml.snakeyaml.error.YAMLException;
+import org.yaml.snakeyaml.introspector.FieldProperty;
+import org.yaml.snakeyaml.introspector.MethodProperty;
+import org.yaml.snakeyaml.introspector.Property;
+import org.yaml.snakeyaml.nodes.MappingNode;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.ScalarNode;
+import org.yaml.snakeyaml.nodes.SequenceNode;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public class Constructor extends SafeConstructor {
+ private final Map<String, Class<? extends Object>> typeTags;
+ private final Map<Class<? extends Object>, TypeDescription> typeDefinitions;
+
+ public Constructor() {
+ this(Object.class);
+ }
+
+ public Constructor(Class<? extends Object> theRoot) {
+ if (theRoot == null) {
+ throw new NullPointerException("Root type must be provided.");
+ }
+ this.yamlConstructors.put(null, new ConstuctYamlObject());
+ rootType = theRoot;
+ typeTags = new HashMap<String, Class<? extends Object>>();
+ typeDefinitions = new HashMap<Class<? extends Object>, TypeDescription>();
+ }
+
+ /**
+ * Create Constructor for a class which does not have to be in the classpath
+ * or for a definition from a Spring ApplicationContext.
+ *
+ * @param theRoot
+ * - fully qualified class name of the root JavaBean
+ * @throws ClassNotFoundException
+ */
+ public Constructor(String theRoot) throws ClassNotFoundException {
+ this(Class.forName(check(theRoot)));
+ }
+
+ private static final String check(String s) {
+ if (s == null) {
+ throw new NullPointerException("Root type must be provided.");
+ }
+ if (s.trim().length() == 0) {
+ throw new YAMLException("Root type must be provided.");
+ }
+ return s;
+ }
+
+ /**
+ * Make YAML aware how to parse a custom Class. If there is no root Class
+ * assigned in constructor then the 'root' property of this definition is
+ * respected.
+ *
+ * @param definition
+ * to be added to the Constructor
+ * @return the previous value associated with <tt>definition</tt>, or
+ * <tt>null</tt> if there was no mapping for <tt>definition</tt>.
+ */
+ public TypeDescription addTypeDescription(TypeDescription definition) {
+ if (definition == null) {
+ throw new NullPointerException("TypeDescription is required.");
+ }
+ if (rootType == Object.class && definition.isRoot()) {
+ rootType = definition.getType();
+ }
+ String tag = definition.getTag();
+ typeTags.put(tag, definition.getType());
+ return typeDefinitions.put(definition.getType(), definition);
+ }
+
+ private class ConstuctYamlObject implements Construct {
+ @SuppressWarnings("unchecked")
+ public Object construct(Node node) {
+ Object result = null;
+ Class<? extends Object> customTag = typeTags.get(node.getTag());
+ try {
+ Class cl;
+ if (customTag == null) {
+ if (node.getTag().length() < "tag:yaml.org,2002:".length()) {
+ throw new YAMLException("Unknown tag: " + node.getTag());
+ }
+ String name = node.getTag().substring("tag:yaml.org,2002:".length());
+ cl = Class.forName(name);
+ } else {
+ cl = customTag;
+ }
+ java.lang.reflect.Constructor javaConstructor;
+ switch (node.getNodeId()) {
+ case mapping:
+ MappingNode mnode = (MappingNode) node;
+ mnode.setType(cl);
+ result = constructMappingNode(mnode);
+ break;
+ case sequence:
+ SequenceNode seqNode = (SequenceNode) node;
+ List<Object> values = (List<Object>) constructSequence(seqNode);
+ Class[] parameterTypes = new Class[values.size()];
+ int index = 0;
+ for (Object parameter : values) {
+ parameterTypes[index] = parameter.getClass();
+ index++;
+ }
+ javaConstructor = cl.getConstructor(parameterTypes);
+ Object[] initargs = values.toArray();
+ result = javaConstructor.newInstance(initargs);
+ break;
+ default:// scalar
+ ScalarNode scaNode = (ScalarNode) node;
+ Object value = constructScalar(scaNode);
+ if (Enum.class.isAssignableFrom(cl)) {
+ String enumValueName = (String) node.getValue();
+ try {
+ result = Enum.valueOf(cl, enumValueName);
+ } catch (Exception ex) {
+ throw new YAMLException("Unable to find enum value '" + enumValueName
+ + "' for enum class: " + cl.getName());
+ }
+ } else {
+ javaConstructor = cl.getConstructor(value.getClass());
+ result = javaConstructor.newInstance(value);
+ }
+ }
+ } catch (Exception e) {
+ throw new ConstructorException(null, null, "Can't construct a java object for "
+ + node.getTag() + "; exception=" + e.getMessage(), node.getStartMark());
+ }
+ return result;
+ }
+ }
+
+ @Override
+ protected Object callConstructor(Node node) {
+ if (Object.class.equals(node.getType())) {
+ return super.callConstructor(node);
+ }
+ Object result;
+ switch (node.getNodeId()) {
+ case scalar:
+ result = constructScalarNode((ScalarNode) node);
+ break;
+ case sequence:
+ result = constructSequence((SequenceNode) node);
+ break;
+ default:// mapping
+ if (Map.class.isAssignableFrom(node.getType())) {
+ result = super.constructMapping((MappingNode) node);
+ } else {
+ result = constructMappingNode((MappingNode) node);
+ }
+ }
+ return result;
+ }
+
+ private Object constructScalarNode(ScalarNode node) {
+ Class<? extends Object> type = node.getType();
+ Object result;
+ if (type.isPrimitive() || type == String.class || Number.class.isAssignableFrom(type)
+ || type == Boolean.class || type == Date.class || type == Character.class
+ || type == BigInteger.class || Enum.class.isAssignableFrom(type)) {
+ if (type == String.class) {
+ Construct stringContructor = yamlConstructors.get("tag:yaml.org,2002:str");
+ result = stringContructor.construct((ScalarNode) node);
+ } else if (type == Boolean.class || type == Boolean.TYPE) {
+ Construct boolContructor = yamlConstructors.get("tag:yaml.org,2002:bool");
+ result = boolContructor.construct((ScalarNode) node);
+ } else if (type == Character.class || type == Character.TYPE) {
+ Construct charContructor = yamlConstructors.get("tag:yaml.org,2002:str");
+ String ch = (String) charContructor.construct((ScalarNode) node);
+ if (ch.length() != 1) {
+ throw new YAMLException("Invalid node Character: '" + ch + "'; length: "
+ + ch.length());
+ }
+ result = new Character(ch.charAt(0));
+ } else if (type == Date.class) {
+ Construct dateContructor = yamlConstructors.get("tag:yaml.org,2002:timestamp");
+ result = dateContructor.construct((ScalarNode) node);
+ } else if (type == Float.class || type == Double.class || type == Float.TYPE
+ || type == Double.TYPE) {
+ Construct doubleContructor = yamlConstructors.get("tag:yaml.org,2002:float");
+ result = doubleContructor.construct(node);
+ if (type == Float.class || type == Float.TYPE) {
+ result = new Float((Double) result);
+ }
+ } else if (Number.class.isAssignableFrom(type) || type == Byte.TYPE
+ || type == Short.TYPE || type == Integer.TYPE || type == Long.TYPE) {
+ Construct intContructor = yamlConstructors.get("tag:yaml.org,2002:int");
+ result = intContructor.construct(node);
+ if (type == Byte.class || type == Byte.TYPE) {
+ result = new Byte(result.toString());
+ } else if (type == Short.class || type == Short.TYPE) {
+ result = new Short(result.toString());
+ } else if (type == Integer.class || type == Integer.TYPE) {
+ result = new Integer(result.toString());
+ } else if (type == Long.class || type == Long.TYPE) {
+ result = new Long(result.toString());
+ } else if (type == BigInteger.class) {
+ result = new BigInteger(result.toString());
+ } else {
+ throw new YAMLException("Unsupported Number class: " + type);
+ }
+ } else if (Enum.class.isAssignableFrom(type)) {
+ String tag = "tag:yaml.org,2002:" + type.getName();
+ node.setTag(tag);
+ result = super.callConstructor(node);
+ } else {
+ throw new YAMLException("Unsupported class: " + type);
+ }
+ } else {
+ try {
+ // get value by BaseConstructor
+ Object value = super.callConstructor(node);
+ if (type.isArray()) {
+ result = value;
+ } else {
+ java.lang.reflect.Constructor<? extends Object> javaConstructor = type
+ .getConstructor(value.getClass());
+ result = javaConstructor.newInstance(value);
+ }
+ } catch (Exception e) {
+ throw new YAMLException(e);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Construct JavaBean. If type safe collections are used please look at
+ * <code>TypeDescription</code>.
+ *
+ * @param node
+ * - node where the keys are property names (they can only be
+ * <code>String</code>s) and values are objects to be created
+ * @return constructed JavaBean
+ */
+ @SuppressWarnings("unchecked")
+ private Object constructMappingNode(MappingNode node) {
+ Class<? extends Object> beanType = node.getType();
+ Object object;
+ try {
+ object = beanType.newInstance();
+ } catch (InstantiationException e) {
+ throw new YAMLException(e);
+ } catch (IllegalAccessException e) {
+ throw new YAMLException(e);
+ }
+ List<Node[]> nodeValue = (List<Node[]>) node.getValue();
+ for (Node[] tuple : nodeValue) {
+ ScalarNode keyNode;
+ if (tuple[0] instanceof ScalarNode) {
+ keyNode = (ScalarNode) tuple[0];// key must be scalar
+ } else {
+ throw new YAMLException("Keys must be scalars but found: " + tuple[0]);
+ }
+ Node valueNode = tuple[1];
+ // keys can only be Strings
+ keyNode.setType(String.class);
+ String key = (String) constructObject(keyNode);
+ boolean isArray = false;
+ try {
+ Property property = getProperty(beanType, key);
+ if (property == null)
+ throw new YAMLException("Unable to find property '" + key + "' on class: "
+ + beanType.getName());
+ valueNode.setType(property.getType());
+ TypeDescription memberDescription = typeDefinitions.get(beanType);
+ if (memberDescription != null) {
+ switch (valueNode.getNodeId()) {
+ case sequence:
+ SequenceNode snode = (SequenceNode) valueNode;
+ Class<? extends Object> memberType = memberDescription
+ .getListPropertyType(key);
+ if (memberType != null) {
+ snode.setListType(memberType);
+ } else if (property.getType().isArray()) {
+ isArray = true;
+ snode.setListType(property.getType().getComponentType());
+ }
+ break;
+ case mapping:
+ MappingNode mnode = (MappingNode) valueNode;
+ Class<? extends Object> keyType = memberDescription.getMapKeyType(key);
+ if (keyType != null) {
+ mnode.setKeyType(keyType);
+ mnode.setValueType(memberDescription.getMapValueType(key));
+ }
+ break;
+ }
+ }
+ Object value = constructObject(valueNode);
+ if (isArray) {
+ List<Object> list = (List<Object>) value;
+ value = list.toArray(createArray(property.getType()));
+ }
+ property.set(object, value);
+ } catch (Exception e) {
+ throw new YAMLException(e);
+ }
+ }
+ return object;
+ }
+
+ @SuppressWarnings("unchecked")
+ private <T> T[] createArray(Class<T> type) {
+ return (T[]) Array.newInstance(type.getComponentType(), 0);
+ }
+
+ protected Property getProperty(Class<? extends Object> type, String name)
+ throws IntrospectionException {
+ for (PropertyDescriptor property : Introspector.getBeanInfo(type).getPropertyDescriptors()) {
+ if (property.getName().equals(name)) {
+ if (property.getReadMethod() != null && property.getWriteMethod() != null)
+ return new MethodProperty(property);
+ break;
+ }
+ }
+ for (Field field : type.getFields()) {
+ int modifiers = field.getModifiers();
+ if (!Modifier.isPublic(modifiers) || Modifier.isStatic(modifiers)
+ || Modifier.isTransient(modifiers))
+ continue;
+ if (field.getName().equals(name))
+ return new FieldProperty(field);
+ }
+ return null;
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/constructor/ConstructorException.java b/src/main/java/org/yaml/snakeyaml/constructor/ConstructorException.java
new file mode 100644
index 00000000..59f952e1
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/constructor/ConstructorException.java
@@ -0,0 +1,19 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.constructor;
+
+import org.yaml.snakeyaml.error.Mark;
+import org.yaml.snakeyaml.error.MarkedYAMLException;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public class ConstructorException extends MarkedYAMLException {
+ private static final long serialVersionUID = -8816339931365239910L;
+
+ protected ConstructorException(String context, Mark contextMark, String problem,
+ Mark problemMark) {
+ super(context, contextMark, problem, problemMark);
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/constructor/SafeConstructor.java b/src/main/java/org/yaml/snakeyaml/constructor/SafeConstructor.java
new file mode 100644
index 00000000..c5de5cc1
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/constructor/SafeConstructor.java
@@ -0,0 +1,402 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.constructor;
+
+import java.math.BigInteger;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.TimeZone;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.yaml.snakeyaml.error.YAMLException;
+import org.yaml.snakeyaml.nodes.MappingNode;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.ScalarNode;
+import org.yaml.snakeyaml.nodes.SequenceNode;
+import org.yaml.snakeyaml.util.Base64Coder;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public class SafeConstructor extends BaseConstructor {
+
+ public SafeConstructor() {
+ this.yamlConstructors.put("tag:yaml.org,2002:null", new ConstuctYamlNull());
+ this.yamlConstructors.put("tag:yaml.org,2002:bool", new ConstuctYamlBool());
+ this.yamlConstructors.put("tag:yaml.org,2002:int", new ConstuctYamlInt());
+ this.yamlConstructors.put("tag:yaml.org,2002:float", new ConstuctYamlFloat());
+ this.yamlConstructors.put("tag:yaml.org,2002:binary", new ConstuctYamlBinary());
+ this.yamlConstructors.put("tag:yaml.org,2002:timestamp", new ConstuctYamlTimestamp());
+ this.yamlConstructors.put("tag:yaml.org,2002:omap", new ConstuctYamlOmap());
+ this.yamlConstructors.put("tag:yaml.org,2002:pairs", new ConstuctYamlPairs());
+ this.yamlConstructors.put("tag:yaml.org,2002:set", new ConstuctYamlSet());
+ this.yamlConstructors.put("tag:yaml.org,2002:str", new ConstuctYamlStr());
+ this.yamlConstructors.put("tag:yaml.org,2002:seq", new ConstuctYamlSeq());
+ this.yamlConstructors.put("tag:yaml.org,2002:map", new ConstuctYamlMap());
+ this.yamlConstructors.put(null, new ConstuctUndefined());
+ }
+
+ private void flattenMapping(MappingNode node) {
+ List<Node[]> merge = new LinkedList<Node[]>();
+ int index = 0;
+ List<Node[]> nodeValue = (List<Node[]>) node.getValue();
+ while (index < nodeValue.size()) {
+ Node keyNode = nodeValue.get(index)[0];
+ Node valueNode = nodeValue.get(index)[1];
+ if (keyNode.getTag().equals("tag:yaml.org,2002:merge")) {
+ nodeValue.remove(index);
+ switch (valueNode.getNodeId()) {
+ case mapping:
+ MappingNode mn = (MappingNode) valueNode;
+ flattenMapping(mn);
+ merge.addAll(mn.getValue());
+ break;
+ case sequence:
+ List<List<Node[]>> submerge = new LinkedList<List<Node[]>>();
+ SequenceNode sn = (SequenceNode) valueNode;
+ List<Node> vals = sn.getValue();
+ for (Node subnode : vals) {
+ if (!(subnode instanceof MappingNode)) {
+ throw new ConstructorException("while constructing a mapping", node
+ .getStartMark(), "expected a mapping for merging, but found "
+ + subnode.getNodeId(), subnode.getStartMark());
+ }
+ MappingNode mnode = (MappingNode) subnode;
+ flattenMapping(mnode);
+ submerge.add(mnode.getValue());
+ }
+ Collections.reverse(submerge);
+ for (List<Node[]> value : submerge) {
+ merge.addAll(value);
+ }
+ break;
+ default:
+ throw new ConstructorException("while constructing a mapping", node
+ .getStartMark(),
+ "expected a mapping or list of mappings for merging, but found "
+ + valueNode.getNodeId(), valueNode.getStartMark());
+ }
+ } else if (keyNode.getTag().equals("tag:yaml.org,2002:value")) {
+ keyNode.setTag("tag:yaml.org,2002:str");
+ index++;
+ } else {
+ index++;
+ }
+ }
+ if (!merge.isEmpty()) {
+ merge.addAll(nodeValue);
+ ((MappingNode) node).setValue(merge);
+ }
+ }
+
+ protected Map<Object, Object> constructMapping(MappingNode node) {
+ flattenMapping(node);
+ return super.constructMapping(node);
+ }
+
+ private class ConstuctYamlNull implements Construct {
+ public Object construct(Node node) {
+ constructScalar((ScalarNode) node);
+ return null;
+ }
+ }
+
+ private final static Map<String, Boolean> BOOL_VALUES = new HashMap<String, Boolean>();
+ static {
+ BOOL_VALUES.put("yes", Boolean.TRUE);
+ BOOL_VALUES.put("no", Boolean.FALSE);
+ BOOL_VALUES.put("true", Boolean.TRUE);
+ BOOL_VALUES.put("false", Boolean.FALSE);
+ BOOL_VALUES.put("on", Boolean.TRUE);
+ BOOL_VALUES.put("off", Boolean.FALSE);
+ }
+
+ private class ConstuctYamlBool implements Construct {
+ public Object construct(Node node) {
+ String val = (String) constructScalar((ScalarNode) node);
+ return BOOL_VALUES.get(val.toLowerCase());
+ }
+ }
+
+ private class ConstuctYamlInt implements Construct {
+ public Object construct(Node node) {
+ String value = constructScalar((ScalarNode) node).toString().replaceAll("_", "");
+ int sign = +1;
+ char first = value.charAt(0);
+ if (first == '-') {
+ sign = -1;
+ value = value.substring(1);
+ } else if (first == '+') {
+ value = value.substring(1);
+ }
+ int base = 10;
+ if (value.equals("0")) {
+ return new Integer(0);
+ } else if (value.startsWith("0b")) {
+ value = value.substring(2);
+ base = 2;
+ } else if (value.startsWith("0x")) {
+ value = value.substring(2);
+ base = 16;
+ } else if (value.startsWith("0")) {
+ value = value.substring(1);
+ base = 8;
+ } else if (value.indexOf(':') != -1) {
+ String[] digits = value.split(":");
+ int bes = 1;
+ int val = 0;
+ for (int i = 0, j = digits.length; i < j; i++) {
+ val += (Long.parseLong(digits[(j - i) - 1]) * bes);
+ bes *= 60;
+ }
+ return createNumber(sign, String.valueOf(val), 10);
+ } else {
+ return createNumber(sign, value, 10);
+ }
+ return createNumber(sign, value, base);
+ }
+ }
+
+ private Number createNumber(int sign, String number, int radix) {
+ Number result;
+ if (sign < 0) {
+ number = "-" + number;
+ }
+ try {
+ int integer = Integer.parseInt(number, radix);
+ result = new Integer(integer);
+ } catch (NumberFormatException e) {
+ try {
+ long longValue = Long.parseLong(number, radix);
+ result = new Long(longValue);
+ } catch (NumberFormatException e1) {
+ result = new BigInteger(number, radix);
+ }
+ }
+ return result;
+ }
+
+ private class ConstuctYamlFloat implements Construct {
+ public Object construct(Node node) {
+ String value = constructScalar((ScalarNode) node).toString().replaceAll("_", "");
+ int sign = +1;
+ char first = value.charAt(0);
+ if (first == '-') {
+ sign = -1;
+ value = value.substring(1);
+ } else if (first == '+') {
+ value = value.substring(1);
+ }
+ String valLower = value.toLowerCase();
+ if (valLower.equals(".inf")) {
+ return new Double(sign == -1 ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY);
+ } else if (valLower.equals(".nan")) {
+ return new Double(Double.NaN);
+ } else if (value.indexOf(':') != -1) {
+ String[] digits = value.split(":");
+ int bes = 1;
+ double val = 0.0;
+ for (int i = 0, j = digits.length; i < j; i++) {
+ val += (Double.parseDouble(digits[(j - i) - 1]) * bes);
+ bes *= 60;
+ }
+ return new Double(sign * val);
+ } else {
+ try {
+ Double d = Double.valueOf(value);
+ return new Double(d.doubleValue() * sign);
+ } catch (NumberFormatException e) {
+ throw new YAMLException("Invalid number: '" + value + "'; in node " + node);
+ }
+ }
+ }
+ }
+
+ private class ConstuctYamlBinary implements Construct {
+ public Object construct(Node node) {
+ byte[] decoded = Base64Coder.decode(constructScalar((ScalarNode) node).toString()
+ .toCharArray());
+ return decoded;
+ }
+ }
+
+ private final static Pattern TIMESTAMP_REGEXP = Pattern
+ .compile("^([0-9][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)(?:(?:[Tt]|[ \t]+)([0-9][0-9]?):([0-9][0-9]):([0-9][0-9])(?:\\.([0-9]*))?(?:[ \t]*(?:Z|([-+][0-9][0-9]?)(?::([0-9][0-9])?)?))?)?$");
+ private final static Pattern YMD_REGEXP = Pattern
+ .compile("^([0-9][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)$");
+
+ private class ConstuctYamlTimestamp implements Construct {
+ public Object construct(Node node) {
+ Matcher match = YMD_REGEXP.matcher((String) node.getValue());
+ if (match.matches()) {
+ String year_s = match.group(1);
+ String month_s = match.group(2);
+ String day_s = match.group(3);
+ Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
+ cal.clear();
+ cal.set(Calendar.YEAR, Integer.parseInt(year_s));
+ // Java's months are zero-based...
+ cal.set(Calendar.MONTH, Integer.parseInt(month_s) - 1); // x
+ cal.set(Calendar.DAY_OF_MONTH, Integer.parseInt(day_s));
+ return cal.getTime();
+ } else {
+ match = TIMESTAMP_REGEXP.matcher((String) node.getValue());
+ if (!match.matches()) {
+ throw new YAMLException("Expected timestamp: " + node);
+ }
+ String year_s = match.group(1);
+ String month_s = match.group(2);
+ String day_s = match.group(3);
+ String hour_s = match.group(4);
+ String min_s = match.group(5);
+ String sec_s = match.group(6);
+ String fract_s = match.group(7);
+ String timezoneh_s = match.group(8);
+ String timezonem_s = match.group(9);
+
+ int usec = 0;
+ if (fract_s != null) {
+ usec = Integer.parseInt(fract_s);
+ if (usec != 0) {
+ while (10 * usec < 1000) {
+ usec *= 10;
+ }
+ }
+ }
+ Calendar cal = Calendar.getInstance();
+ cal.set(Calendar.YEAR, Integer.parseInt(year_s));
+ // Java's months are zero-based...
+ cal.set(Calendar.MONTH, Integer.parseInt(month_s) - 1);
+ cal.set(Calendar.DAY_OF_MONTH, Integer.parseInt(day_s));
+ cal.set(Calendar.HOUR_OF_DAY, Integer.parseInt(hour_s));
+ cal.set(Calendar.MINUTE, Integer.parseInt(min_s));
+ cal.set(Calendar.SECOND, Integer.parseInt(sec_s));
+ cal.set(Calendar.MILLISECOND, usec);
+ if (timezoneh_s != null || timezonem_s != null) {
+ int zone = 0;
+ int sign = +1;
+ if (timezoneh_s != null) {
+ if (timezoneh_s.startsWith("-")) {
+ sign = -1;
+ }
+ zone += Integer.parseInt(timezoneh_s.substring(1)) * 3600000;
+ }
+ if (timezonem_s != null) {
+ zone += Integer.parseInt(timezonem_s) * 60000;
+ }
+ cal.set(Calendar.ZONE_OFFSET, sign * zone);
+ } else {
+ cal.setTimeZone(TimeZone.getTimeZone("UTC"));
+ }
+ return cal.getTime();
+ }
+ }
+ }
+
+ private class ConstuctYamlOmap implements Construct {
+ public Object construct(Node node) {
+ // Note: we do not check for duplicate keys, because it's too
+ // CPU-expensive.
+ Map<Object, Object> omap = new LinkedHashMap<Object, Object>();
+ if (!(node instanceof SequenceNode)) {
+ throw new ConstructorException("while constructing an ordered map", node
+ .getStartMark(), "expected a sequence, but found " + node.getNodeId(), node
+ .getStartMark());
+ }
+ SequenceNode snode = (SequenceNode) node;
+ for (Node subnode : snode.getValue()) {
+ if (!(subnode instanceof MappingNode)) {
+ throw new ConstructorException("while constructing an ordered map", node
+ .getStartMark(), "expected a mapping of length 1, but found "
+ + subnode.getNodeId(), subnode.getStartMark());
+ }
+ MappingNode mnode = (MappingNode) subnode;
+ if (mnode.getValue().size() != 1) {
+ throw new ConstructorException("while constructing an ordered map", node
+ .getStartMark(), "expected a single mapping item, but found "
+ + mnode.getValue().size() + " items", mnode.getStartMark());
+ }
+ Node keyNode = mnode.getValue().get(0)[0];
+ Node valueNode = mnode.getValue().get(0)[1];
+ Object key = constructObject(keyNode);
+ Object value = constructObject(valueNode);
+ omap.put(key, value);
+ }
+ return omap;
+ }
+ }
+
+ // Note: the same code as `construct_yaml_omap`.
+ private class ConstuctYamlPairs implements Construct {
+ public Object construct(Node node) {
+ // Note: we do not check for duplicate keys, because it's too
+ // CPU-expensive.
+ List<Object[]> pairs = new LinkedList<Object[]>();
+ if (!(node instanceof SequenceNode)) {
+ throw new ConstructorException("while constructing pairs", node.getStartMark(),
+ "expected a sequence, but found " + node.getNodeId(), node.getStartMark());
+ }
+ SequenceNode snode = (SequenceNode) node;
+ for (Node subnode : snode.getValue()) {
+ if (!(subnode instanceof MappingNode)) {
+ throw new ConstructorException("while constructingpairs", node.getStartMark(),
+ "expected a mapping of length 1, but found " + subnode.getNodeId(),
+ subnode.getStartMark());
+ }
+ MappingNode mnode = (MappingNode) subnode;
+ if (mnode.getValue().size() != 1) {
+ throw new ConstructorException("while constructing pairs", node.getStartMark(),
+ "expected a single mapping item, but found " + mnode.getValue().size()
+ + " items", mnode.getStartMark());
+ }
+ Node keyNode = mnode.getValue().get(0)[0];
+ Node valueNode = mnode.getValue().get(0)[1];
+ Object key = constructObject(keyNode);
+ Object value = constructObject(valueNode);
+ pairs.add(new Object[] { key, value });
+ }
+ return pairs;
+ }
+ }
+
+ private class ConstuctYamlSet implements Construct {
+ public Object construct(Node node) {
+ Map<Object, Object> value = constructMapping((MappingNode) node);
+ return value.keySet();
+ }
+ }
+
+ private class ConstuctYamlStr implements Construct {
+ public Object construct(Node node) {
+ String value = (String) constructScalar((ScalarNode) node);
+ return value;
+ }
+ }
+
+ private class ConstuctYamlSeq implements Construct {
+ public Object construct(Node node) {
+ return constructSequence((SequenceNode) node);
+ }
+ }
+
+ private class ConstuctYamlMap implements Construct {
+ public Object construct(Node node) {
+ return constructMapping((MappingNode) node);
+ }
+ }
+
+ private class ConstuctUndefined implements Construct {
+ public Object construct(Node node) {
+ throw new ConstructorException(null, null,
+ "could not determine a constructor for the tag " + node.getTag(), node
+ .getStartMark());
+ }
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/emitter/Emitter.java b/src/main/java/org/yaml/snakeyaml/emitter/Emitter.java
new file mode 100644
index 00000000..36b62e92
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/emitter/Emitter.java
@@ -0,0 +1,1422 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.emitter;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Queue;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.regex.Pattern;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.events.AliasEvent;
+import org.yaml.snakeyaml.events.CollectionEndEvent;
+import org.yaml.snakeyaml.events.CollectionStartEvent;
+import org.yaml.snakeyaml.events.DocumentEndEvent;
+import org.yaml.snakeyaml.events.DocumentStartEvent;
+import org.yaml.snakeyaml.events.Event;
+import org.yaml.snakeyaml.events.MappingEndEvent;
+import org.yaml.snakeyaml.events.MappingStartEvent;
+import org.yaml.snakeyaml.events.NodeEvent;
+import org.yaml.snakeyaml.events.ScalarEvent;
+import org.yaml.snakeyaml.events.SequenceEndEvent;
+import org.yaml.snakeyaml.events.SequenceStartEvent;
+import org.yaml.snakeyaml.events.StreamEndEvent;
+import org.yaml.snakeyaml.events.StreamStartEvent;
+
+/**
+ * <pre>
+ * Emitter expects events obeying the following grammar:
+ * stream ::= STREAM-START document* STREAM-END
+ * document ::= DOCUMENT-START node DOCUMENT-END
+ * node ::= SCALAR | sequence | mapping
+ * sequence ::= SEQUENCE-START node* SEQUENCE-END
+ * mapping ::= MAPPING-START (node node)* MAPPING-END
+ * </pre>
+ *
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public final class Emitter {
+ private static final Map<Character, String> ESCAPE_REPLACEMENTS = new HashMap<Character, String>();
+ public static final int MIN_INDENT = 1;
+ public static final int MAX_INDENT = 10;
+
+ static {
+ ESCAPE_REPLACEMENTS.put(new Character('\0'), "0");
+ ESCAPE_REPLACEMENTS.put(new Character('\u0007'), "a");
+ ESCAPE_REPLACEMENTS.put(new Character('\u0008'), "b");
+ ESCAPE_REPLACEMENTS.put(new Character('\u0009'), "t");
+ ESCAPE_REPLACEMENTS.put(new Character('\n'), "n");
+ ESCAPE_REPLACEMENTS.put(new Character('\u000B'), "v");
+ ESCAPE_REPLACEMENTS.put(new Character('\u000C'), "f");
+ ESCAPE_REPLACEMENTS.put(new Character('\r'), "r");
+ ESCAPE_REPLACEMENTS.put(new Character('\u001B'), "e");
+ ESCAPE_REPLACEMENTS.put(new Character('"'), "\"");
+ ESCAPE_REPLACEMENTS.put(new Character('\\'), "\\");
+ ESCAPE_REPLACEMENTS.put(new Character('\u0085'), "N");
+ ESCAPE_REPLACEMENTS.put(new Character('\u00A0'), "_");
+ ESCAPE_REPLACEMENTS.put(new Character('\u2028'), "L");
+ ESCAPE_REPLACEMENTS.put(new Character('\u2029'), "P");
+ }
+
+ private final static Map<String, String> DEFAULT_TAG_PREFIXES = new LinkedHashMap<String, String>();
+ static {
+ DEFAULT_TAG_PREFIXES.put("!", "!");
+ DEFAULT_TAG_PREFIXES.put("tag:yaml.org,2002:", "!!");
+ }
+ // The stream should have the methods `write` and possibly `flush`.
+ private final Writer stream;
+
+ // Encoding is defined by Writer (cannot be overriden by STREAM-START.)
+ // private Charset encoding;
+
+ // Emitter is a state machine with a stack of states to handle nested
+ // structures.
+ private final LinkedList<EmitterState> states;
+ private EmitterState state;
+
+ // Current event and the event queue.
+ private final Queue<Event> events;
+ private Event event;
+
+ // The current indentation level and the stack of previous indents.
+ private final LinkedList<Integer> indents;
+ private Integer indent;
+
+ // Flow level.
+ private int flowLevel;
+
+ // Contexts.
+ private boolean rootContext;
+ private boolean mappingContext;
+ private boolean simpleKeyContext;
+
+ //
+ // Characteristics of the last emitted character:
+ // - current position.
+ // - is it a whitespace?
+ // - is it an indention character
+ // (indentation space, '-', '?', or ':')?
+ private int line;
+ private int column;
+ private boolean whitespace;
+ private boolean indention;
+ private boolean openEnded;
+
+ // Formatting details.
+ private Boolean canonical;
+ private boolean allowUnicode;
+ private int bestIndent;
+ private int bestWidth;
+ private String bestLineBreak;
+
+ // Tag prefixes.
+ private Map<String, String> tagPrefixes;
+
+ // Prepared anchor and tag.
+ private String preparedAnchor;
+ private String preparedTag;
+
+ // Scalar analysis and style.
+ private ScalarAnalysis analysis;
+ private char style = 0;
+
+ public Emitter(Writer stream, DumperOptions opts) {
+ // The stream should have the methods `write` and possibly `flush`.
+ this.stream = stream;
+ // Emitter is a state machine with a stack of states to handle nested
+ // structures.
+ this.states = new LinkedList<EmitterState>();
+ this.state = new ExpectStreamStart();
+ // Current event and the event queue.
+ this.events = new LinkedList<Event>();
+ this.event = null;
+ // The current indentation level and the stack of previous indents.
+ this.indents = new LinkedList<Integer>();
+ this.indent = null;
+ // Flow level.
+ this.flowLevel = 0;
+ // Contexts.
+ mappingContext = false;
+ simpleKeyContext = false;
+
+ //
+ // Characteristics of the last emitted character:
+ // - current position.
+ // - is it a whitespace?
+ // - is it an indention character
+ // (indentation space, '-', '?', or ':')?
+ line = 0;
+ column = 0;
+ whitespace = true;
+ indention = true;
+
+ // Whether the document requires an explicit document indicator
+ openEnded = false;
+
+ // Formatting details.
+ this.canonical = opts.isCanonical();
+ this.allowUnicode = opts.isAllowUnicode();
+ this.bestIndent = 2;
+ if ((opts.getIndent() > MIN_INDENT) && (opts.getIndent() < MAX_INDENT)) {
+ this.bestIndent = opts.getIndent();
+ }
+ this.bestWidth = 80;
+ if (opts.getWidth() > this.bestIndent * 2) {
+ this.bestWidth = opts.getWidth();
+ }
+ this.bestLineBreak = opts.getLineBreak().getString();
+
+ // Tag prefixes.
+ this.tagPrefixes = new LinkedHashMap<String, String>();
+
+ // Prepared anchor and tag.
+ this.preparedAnchor = null;
+ this.preparedTag = null;
+
+ // Scalar analysis and style.
+ this.analysis = null;
+ this.style = (char) 0;
+ }
+
+ public void emit(Event event) throws IOException {
+ this.events.offer(event);
+ while (!needMoreEvents()) {
+ this.event = this.events.poll();
+ this.state.expect();
+ this.event = null;
+ }
+ }
+
+ // In some cases, we wait for a few next events before emitting.
+
+ private boolean needMoreEvents() {
+ if (events.isEmpty()) {
+ return true;
+ }
+ Event event = events.peek();
+ if (event instanceof DocumentStartEvent) {
+ return needEvents(1);
+ } else if (event instanceof SequenceStartEvent) {
+ return needEvents(2);
+ } else if (event instanceof MappingStartEvent) {
+ return needEvents(3);
+ } else {
+ return false;
+ }
+ }
+
+ private boolean needEvents(int count) {
+ int level = 0;
+ Iterator<Event> iter = events.iterator();
+ iter.next();
+ while (iter.hasNext()) {
+ Event event = iter.next();
+ if (event instanceof DocumentStartEvent || event instanceof CollectionStartEvent) {
+ level++;
+ } else if (event instanceof DocumentEndEvent || event instanceof CollectionEndEvent) {
+ level--;
+ } else if (event instanceof StreamEndEvent) {
+ level = -1;
+ }
+ if (level < 0) {
+ return false;
+ }
+ }
+ return events.size() < count + 1;
+ }
+
+ private void increaseIndent(boolean flow, boolean indentless) {
+ indents.addFirst(indent);
+ if (indent == null) {
+ if (flow) {
+ indent = bestIndent;
+ } else {
+ indent = 0;
+ }
+ } else if (!indentless) {
+ this.indent += bestIndent;
+ }
+ }
+
+ // States
+
+ // Stream handlers.
+
+ private class ExpectStreamStart implements EmitterState {
+ public void expect() throws IOException {
+ if (event instanceof StreamStartEvent) {
+ writeStreamStart();
+ state = new ExpectFirstDocumentStart();
+ } else {
+ throw new EmitterException("expected StreamStartEvent, but got " + event);
+ }
+ }
+ }
+
+ private class ExpectNothing implements EmitterState {
+ public void expect() throws IOException {
+ throw new EmitterException("expecting nothing, but got " + event);
+ }
+ }
+
+ // Document handlers.
+
+ private class ExpectFirstDocumentStart implements EmitterState {
+ public void expect() throws IOException {
+ new ExpectDocumentStart(true).expect();
+ }
+ }
+
+ private class ExpectDocumentStart implements EmitterState {
+ private boolean first;
+
+ public ExpectDocumentStart(boolean first) {
+ this.first = first;
+ }
+
+ public void expect() throws IOException {
+ if (event instanceof DocumentStartEvent) {
+ DocumentStartEvent ev = (DocumentStartEvent) event;
+ if ((ev.getVersion() != null || ev.getTags() != null) && openEnded) {
+ writeIndicator("...", true, false, false);
+ writeIndent();
+ }
+ if (ev.getVersion() != null) {
+ String versionText = prepareVersion(ev.getVersion());
+ writeVersionDirective(versionText);
+ }
+ tagPrefixes = new LinkedHashMap<String, String>(DEFAULT_TAG_PREFIXES);
+ if (ev.getTags() != null) {
+ Set<String> handles = new TreeSet<String>(ev.getTags().keySet());
+ for (String handle : handles) {
+ String prefix = ev.getTags().get(handle);
+ tagPrefixes.put(prefix, handle);
+ String handleText = prepareTagHandle(handle);
+ String prefixText = prepareTagPrefix(prefix);
+ writeTagDirective(handleText, prefixText);
+ }
+ }
+ boolean implicit = first && !ev.getExplicit() && !canonical
+ && ev.getVersion() == null && ev.getTags() == null && !checkEmptyDocument();
+ if (!implicit) {
+ writeIndent();
+ writeIndicator("---", true, false, false);
+ if (canonical) {
+ writeIndent();
+ }
+ }
+ state = new ExpectDocumentRoot();
+ } else if (event instanceof StreamEndEvent) {
+ // TODO fix 313 PyYAML changeset
+ // if (openEnded) {
+ // writeIndicator("...", true, false, false);
+ // writeIndent();
+ // }
+ writeStreamEnd();
+ state = new ExpectNothing();
+ } else {
+ throw new EmitterException("expected DocumentStartEvent, but got " + event);
+ }
+ }
+ }
+
+ private class ExpectDocumentEnd implements EmitterState {
+ public void expect() throws IOException {
+ if (event instanceof DocumentEndEvent) {
+ writeIndent();
+ if (((DocumentEndEvent) event).getExplicit()) {
+ writeIndicator("...", true, false, false);
+ writeIndent();
+ }
+ flushStream();
+ state = new ExpectDocumentStart(false);
+ } else {
+ throw new EmitterException("expected DocumentEndEvent, but got " + event);
+ }
+ }
+ }
+
+ private class ExpectDocumentRoot implements EmitterState {
+ public void expect() throws IOException {
+ states.addFirst(new ExpectDocumentEnd());
+ expectNode(true, false, false, false);
+ }
+ }
+
+ // Node handlers.
+
+ private void expectNode(boolean root, boolean sequence, boolean mapping, boolean simpleKey)
+ throws IOException {
+ rootContext = root;
+ mappingContext = mapping;
+ simpleKeyContext = simpleKey;
+ if (event instanceof AliasEvent) {
+ expectAlias();
+ } else if (event instanceof ScalarEvent || event instanceof CollectionStartEvent) {
+ processAnchor("&");
+ processTag();
+ if (event instanceof ScalarEvent) {
+ expectScalar();
+ } else if (event instanceof SequenceStartEvent) {
+ if (flowLevel != 0 || canonical || ((SequenceStartEvent) event).getFlowStyle()
+ || checkEmptySequence()) {
+ expectFlowSequence();
+ } else {
+ expectBlockSequence();
+ }
+ } else {// MappingStartEvent
+ if (flowLevel != 0 || canonical || ((MappingStartEvent) event).getFlowStyle()
+ || checkEmptyMapping()) {
+ expectFlowMapping();
+ } else {
+ expectBlockMapping();
+ }
+ }
+ } else {
+ throw new EmitterException("expected NodeEvent, but got " + event);
+ }
+ }
+
+ private void expectAlias() throws IOException {
+ if (((NodeEvent) event).getAnchor() == null) {
+ throw new EmitterException("anchor is not specified for alias");
+ }
+ processAnchor("*");
+ state = states.removeFirst();
+ }
+
+ private void expectScalar() throws IOException {
+ increaseIndent(true, false);
+ processScalar();
+ indent = indents.removeFirst();
+ state = states.removeFirst();
+ }
+
+ // Flow sequence handlers.
+
+ private void expectFlowSequence() throws IOException {
+ writeIndicator("[", true, true, false);
+ flowLevel++;
+ increaseIndent(true, false);
+ state = new ExpectFirstFlowSequenceItem();
+ }
+
+ private class ExpectFirstFlowSequenceItem implements EmitterState {
+ public void expect() throws IOException {
+ if (event instanceof SequenceEndEvent) {
+ indent = indents.removeFirst();
+ flowLevel--;
+ writeIndicator("]", false, false, false);
+ state = states.removeFirst();
+ } else {
+ if (canonical || column > bestWidth) {
+ writeIndent();
+ }
+ states.addFirst(new ExpectFlowSequenceItem());
+ expectNode(false, true, false, false);
+ }
+ }
+ }
+
+ private class ExpectFlowSequenceItem implements EmitterState {
+ public void expect() throws IOException {
+ if (event instanceof SequenceEndEvent) {
+ indent = indents.removeFirst();
+ flowLevel--;
+ if (canonical) {
+ writeIndicator(",", false, false, false);
+ writeIndent();
+ }
+ writeIndicator("]", false, false, false);
+ state = states.removeFirst();
+ } else {
+ writeIndicator(",", false, false, false);
+ if (canonical || column > bestWidth) {
+ writeIndent();
+ }
+ states.addFirst(new ExpectFlowSequenceItem());
+ expectNode(false, true, false, false);
+ }
+ }
+ }
+
+ // Flow mapping handlers.
+
+ private void expectFlowMapping() throws IOException {
+ writeIndicator("{", true, true, false);
+ flowLevel++;
+ increaseIndent(true, false);
+ state = new ExpectFirstFlowMappingKey();
+ }
+
+ private class ExpectFirstFlowMappingKey implements EmitterState {
+ public void expect() throws IOException {
+ if (event instanceof MappingEndEvent) {
+ indent = indents.removeFirst();
+ flowLevel--;
+ writeIndicator("}", false, false, false);
+ state = states.removeFirst();
+ } else {
+ if (canonical || column > bestWidth) {
+ writeIndent();
+ }
+ if (!canonical && checkSimpleKey()) {
+ states.addFirst(new ExpectFlowMappingSimpleValue());
+ expectNode(false, false, true, true);
+ } else {
+ writeIndicator("?", true, false, false);
+ states.addFirst(new ExpectFlowMappingValue());
+ expectNode(false, false, true, false);
+ }
+ }
+ }
+ }
+
+ private class ExpectFlowMappingKey implements EmitterState {
+ public void expect() throws IOException {
+ if (event instanceof MappingEndEvent) {
+ indent = indents.removeFirst();
+ flowLevel--;
+ if (canonical) {
+ writeIndicator(",", false, false, false);
+ writeIndent();
+ }
+ writeIndicator("}", false, false, false);
+ state = states.removeFirst();
+ } else {
+ writeIndicator(",", false, false, false);
+ if (canonical || column > bestWidth) {
+ writeIndent();
+ }
+ if (!canonical && checkSimpleKey()) {
+ states.addFirst(new ExpectFlowMappingSimpleValue());
+ expectNode(false, false, true, true);
+ } else {
+ writeIndicator("?", true, false, false);
+ states.addFirst(new ExpectFlowMappingValue());
+ expectNode(false, false, true, false);
+ }
+ }
+ }
+ }
+
+ private class ExpectFlowMappingSimpleValue implements EmitterState {
+ public void expect() throws IOException {
+ writeIndicator(":", false, false, false);
+ states.addFirst(new ExpectFlowMappingKey());
+ expectNode(false, false, true, false);
+ }
+ }
+
+ private class ExpectFlowMappingValue implements EmitterState {
+ public void expect() throws IOException {
+ if (canonical || column > bestWidth) {
+ writeIndent();
+ }
+ writeIndicator(":", true, false, false);
+ states.addFirst(new ExpectFlowMappingKey());
+ expectNode(false, false, true, false);
+ }
+ }
+
+ // Block sequence handlers.
+
+ private void expectBlockSequence() throws IOException {
+ boolean indentless = (mappingContext && !indention);
+ increaseIndent(false, indentless);
+ state = new ExpectFirstBlockSequenceItem();
+ }
+
+ private class ExpectFirstBlockSequenceItem implements EmitterState {
+ public void expect() throws IOException {
+ new ExpectBlockSequenceItem(true).expect();
+ }
+ }
+
+ private class ExpectBlockSequenceItem implements EmitterState {
+ private boolean first;
+
+ public ExpectBlockSequenceItem(boolean first) {
+ this.first = first;
+ }
+
+ public void expect() throws IOException {
+ if (!this.first && event instanceof SequenceEndEvent) {
+ indent = indents.removeFirst();
+ state = states.removeFirst();
+ } else {
+ writeIndent();
+ writeIndicator("-", true, false, true);
+ states.addFirst(new ExpectBlockSequenceItem(false));
+ expectNode(false, true, false, false);
+ }
+ }
+ }
+
+ // Block mapping handlers.
+ private void expectBlockMapping() throws IOException {
+ increaseIndent(false, false);
+ state = new ExpectFirstBlockMappingKey();
+ }
+
+ private class ExpectFirstBlockMappingKey implements EmitterState {
+ public void expect() throws IOException {
+ new ExpectBlockMappingKey(true).expect();
+ }
+ }
+
+ private class ExpectBlockMappingKey implements EmitterState {
+ private boolean first;
+
+ public ExpectBlockMappingKey(boolean first) {
+ this.first = first;
+ }
+
+ public void expect() throws IOException {
+ if (!this.first && event instanceof MappingEndEvent) {
+ indent = indents.removeFirst();
+ state = states.removeFirst();
+ } else {
+ writeIndent();
+ if (checkSimpleKey()) {
+ states.addFirst(new ExpectBlockMappingSimpleValue());
+ expectNode(false, false, true, true);
+ } else {
+ writeIndicator("?", true, false, true);
+ states.addFirst(new ExpectBlockMappingValue());
+ expectNode(false, false, true, false);
+ }
+ }
+ }
+ }
+
+ private class ExpectBlockMappingSimpleValue implements EmitterState {
+ public void expect() throws IOException {
+ writeIndicator(":", false, false, false);
+ states.addFirst(new ExpectBlockMappingKey(false));
+ expectNode(false, false, true, false);
+ }
+ }
+
+ private class ExpectBlockMappingValue implements EmitterState {
+ public void expect() throws IOException {
+ writeIndent();
+ writeIndicator(":", true, false, true);
+ states.addFirst(new ExpectBlockMappingKey(false));
+ expectNode(false, false, true, false);
+ }
+ }
+
+ // Checkers.
+
+ private boolean checkEmptySequence() {
+ return (event instanceof SequenceStartEvent && !events.isEmpty() && events.peek() instanceof SequenceEndEvent);
+ }
+
+ private boolean checkEmptyMapping() {
+ return (event instanceof MappingStartEvent && !events.isEmpty() && events.peek() instanceof MappingEndEvent);
+ }
+
+ private boolean checkEmptyDocument() {
+ if (!(event instanceof DocumentStartEvent) || events.isEmpty()) {
+ return false;
+ }
+ Event event = events.peek();
+ if (event instanceof ScalarEvent) {
+ ScalarEvent e = (ScalarEvent) event;
+ return (e.getAnchor() == null && e.getTag() == null && e.getImplicit() != null && e
+ .getValue() == "");
+ } else {
+ return false;
+ }
+ }
+
+ private boolean checkSimpleKey() {
+ int length = 0;
+ if (event instanceof NodeEvent && ((NodeEvent) event).getAnchor() != null) {
+ if (preparedAnchor == null) {
+ preparedAnchor = prepareAnchor(((NodeEvent) event).getAnchor());
+ }
+ length += preparedAnchor.length();
+ }
+ String tag = null;
+ if (event instanceof ScalarEvent) {
+ tag = ((ScalarEvent) event).getTag();
+ } else if (event instanceof CollectionStartEvent) {
+ tag = ((CollectionStartEvent) event).getTag();
+ }
+ if (tag != null) {
+ if (preparedTag == null) {
+ preparedTag = prepareTag(tag);
+ }
+ length += preparedTag.length();
+ }
+ if (event instanceof ScalarEvent) {
+ if (analysis == null) {
+ analysis = analyzeScalar(((ScalarEvent) event).getValue());
+ }
+ length += analysis.scalar.length();
+ }
+ return (length < 128 && (event instanceof AliasEvent
+ || (event instanceof ScalarEvent && !analysis.empty && !analysis.multiline)
+ || checkEmptySequence() || checkEmptyMapping()));
+ }
+
+ // Anchor, Tag, and Scalar processors.
+
+ private void processAnchor(String indicator) throws IOException {
+ NodeEvent ev = (NodeEvent) event;
+ if (ev.getAnchor() == null) {
+ preparedAnchor = null;
+ return;
+ }
+ if (preparedAnchor == null) {
+ preparedAnchor = prepareAnchor(ev.getAnchor());
+ }
+ if (preparedAnchor != null && !"".equals(preparedAnchor)) {
+ writeIndicator(indicator + preparedAnchor, true, false, false);
+ }
+ preparedAnchor = null;
+ }
+
+ private void processTag() throws IOException {
+ String tag = null;
+ if (event instanceof ScalarEvent) {
+ ScalarEvent ev = (ScalarEvent) event;
+ tag = ev.getTag();
+ if (style == 0) {
+ style = chooseScalarStyle();
+ }
+ if (((!canonical || tag == null) && ((style == 0 && ev.getImplicit()[0]) || (style != 0 && ev
+ .getImplicit()[1])))) {
+ preparedTag = null;
+ return;
+ }
+ if (ev.getImplicit()[0] && tag == null) {
+ tag = "!";
+ preparedTag = null;
+ }
+ } else {
+ CollectionStartEvent ev = (CollectionStartEvent) event;
+ tag = ev.getTag();
+ if ((!canonical || tag == null) && ev.getImplicit()) {
+ preparedTag = null;
+ return;
+ }
+ }
+ if (tag == null) {
+ throw new EmitterException("tag is not specified");
+ }
+ if (preparedTag == null) {
+ preparedTag = prepareTag(tag);
+ }
+ if (preparedTag != null && !"".equals(preparedTag)) {
+ writeIndicator(preparedTag, true, false, false);
+ }
+ preparedTag = null;
+ }
+
+ private char chooseScalarStyle() {
+ ScalarEvent ev = (ScalarEvent) event;
+ if (analysis == null) {
+ analysis = analyzeScalar(ev.getValue());
+ }
+ if (ev.getStyle() != null && ev.getStyle() == '"' || this.canonical) {
+ return '"';
+ }
+ if (ev.getStyle() == null && ev.getImplicit()[0]) {
+ if (!(simpleKeyContext && (analysis.empty || analysis.multiline))
+ && ((flowLevel != 0 && analysis.allowFlowPlain) || (flowLevel == 0 && analysis.allowBlockPlain))) {
+ return 0;
+ }
+ }
+ if (ev.getStyle() != null && (ev.getStyle() == '|' || ev.getStyle() == '>')) {
+ if (flowLevel == 0 && !simpleKeyContext && analysis.allowBlock) {
+ return ev.getStyle();
+ }
+ }
+ if (ev.getStyle() == null || ev.getStyle() == '\'') {
+ if (analysis.allowSingleQuoted && !(simpleKeyContext && analysis.multiline)) {
+ return '\'';
+ }
+ }
+ return '"';
+ }
+
+ private void processScalar() throws IOException {
+ ScalarEvent ev = (ScalarEvent) event;
+ if (analysis == null) {
+ analysis = analyzeScalar(ev.getValue());
+ }
+ if (style == 0) {
+ style = chooseScalarStyle();
+ }
+ boolean split = !simpleKeyContext;
+ if (style == '"') {
+ writeDoubleQuoted(analysis.scalar, split);
+ } else if (style == '\'') {
+ writeSingleQuoted(analysis.scalar, split);
+ } else if (style == '>') {
+ writeFolded(analysis.scalar);
+ } else if (style == '|') {
+ writeLiteral(analysis.scalar);
+ } else {
+ writePlain(analysis.scalar, split);
+ }
+ analysis = null;
+ style = 0;
+ }
+
+ // Analyzers.
+
+ private String prepareVersion(Integer[] version) {
+ Integer major = version[0];
+ Integer minor = version[1];
+ if (major != 1) {
+ throw new EmitterException("unsupported YAML version: " + version[0] + "." + version[1]);
+ }
+ return major.toString() + "." + minor.toString();
+ }
+
+ private final static Pattern HANDLE_FORMAT = Pattern.compile("^![-_\\w]*!$");
+
+ private String prepareTagHandle(String handle) {
+ if (handle == null || "".equals(handle)) {
+ throw new EmitterException("tag handle must not be empty");
+ } else if (handle.charAt(0) != '!' || handle.charAt(handle.length() - 1) != '!') {
+ throw new EmitterException("tag handle must start and end with '!': " + handle);
+ } else if (!"!".equals(handle) && !HANDLE_FORMAT.matcher(handle).matches()) {
+ throw new EmitterException("invalid character in the tag handle: " + handle);
+ }
+ return handle;
+ }
+
+ private String prepareTagPrefix(String prefix) {
+ if (prefix == null || "".equals(prefix)) {
+ throw new EmitterException("tag prefix must not be empty");
+ }
+ StringBuffer chunks = new StringBuffer();
+ int start = 0;
+ int end = 0;
+ if (prefix.charAt(0) == '!') {
+ end = 1;
+ }
+ while (end < prefix.length()) {
+ end++;
+ }
+ if (start < end) {
+ chunks.append(prefix.substring(start, end));
+ }
+ return chunks.toString();
+ }
+
+ private String prepareTag(String tag) {
+ if (tag == null || "".equals(tag)) {
+ throw new EmitterException("tag must not be empty");
+ }
+ if (tag.equals("!")) {
+ return tag;
+ }
+ String handle = null;
+ String suffix = tag;
+ for (String prefix : tagPrefixes.keySet()) {
+ if (tag.startsWith(prefix) && (prefix.equals("!") || prefix.length() < tag.length())) {
+ handle = tagPrefixes.get(prefix);
+ suffix = tag.substring(prefix.length());
+ }
+ }
+ StringBuffer chunks = new StringBuffer();
+ int start = 0;
+ int end = 0;
+ while (end < suffix.length()) {
+ end++;
+ }
+ if (start < end) {
+ chunks.append(suffix.substring(start, end));
+ }
+ String suffixText = chunks.toString();
+ if (handle != null) {
+ return handle + suffixText;
+ } else {
+ return "!<" + suffixText + ">";
+ }
+ }
+
+ private final static Pattern ANCHOR_FORMAT = Pattern.compile("^[-_\\w]*$");
+
+ static String prepareAnchor(String anchor) {
+ if (anchor == null || "".equals(anchor)) {
+ throw new EmitterException("anchor must not be empty");
+ }
+ if (!ANCHOR_FORMAT.matcher(anchor).matches()) {
+ throw new EmitterException("invalid character in the anchor: " + anchor);
+ }
+ return anchor;
+ }
+
+ private ScalarAnalysis analyzeScalar(String scalar) {
+ // Empty scalar is a special case.
+ if (scalar == null || "".equals(scalar)) {
+ return new ScalarAnalysis(scalar, true, false, false, true, true, true, false);
+ }
+ // Indicators and special characters.
+ boolean blockIndicators = false;
+ boolean flowIndicators = false;
+ boolean lineBreaks = false;
+ boolean specialCharacters = false;
+
+ // Important whitespace combinations.
+ boolean leadingSpace = false;
+ boolean leadingBreak = false;
+ boolean trailingSpace = false;
+ boolean trailingBreak = false;
+ boolean breakSpace = false;
+ boolean spaceBreak = false;
+
+ // Check document indicators.
+ if (scalar.startsWith("---") || scalar.startsWith("...")) {
+ blockIndicators = true;
+ flowIndicators = true;
+ }
+ // First character or preceded by a whitespace.
+ boolean preceededByWhitespace = true;
+ boolean followedByWhitespace = (scalar.length() == 1 || "\0 \t\r\n\u0085\u2029\u2029"
+ .indexOf(scalar.charAt(1)) != -1);
+ // The previous character is a space.
+ boolean previousSpace = false;
+
+ // The previous character is a break.
+ boolean previousBreak = false;
+
+ int index = 0;
+
+ while (index < scalar.length()) {
+ char ch = scalar.charAt(index);
+ // Check for indicators.
+ if (index == 0) {
+ // Leading indicators are special characters.
+ if ("#,[]{}&*!|>\'\"%@`".indexOf(ch) != -1) {
+ flowIndicators = true;
+ blockIndicators = true;
+ }
+ if (ch == '?' || ch == ':') {
+ flowIndicators = true;
+ if (followedByWhitespace) {
+ blockIndicators = true;
+ }
+ }
+ if (ch == '-' && followedByWhitespace) {
+ flowIndicators = true;
+ blockIndicators = true;
+ }
+ } else {
+ // Some indicators cannot appear within a scalar as well.
+ if (",?[]{}".indexOf(ch) != -1) {
+ flowIndicators = true;
+ }
+ if (ch == ':') {
+ flowIndicators = true;
+ if (followedByWhitespace) {
+ blockIndicators = true;
+ }
+ }
+ if (ch == '#' && preceededByWhitespace) {
+ flowIndicators = true;
+ blockIndicators = true;
+ }
+ }
+ // Check for line breaks, special, and unicode characters.
+ if (ch == '\n' || ch == '\u0085' || ch == '\u2028' || ch == '\u2029') {
+ lineBreaks = true;
+ }
+ if (!(ch == '\n' || ('\u0020' <= ch && ch <= '\u007E'))) {
+ if ((ch == '\u0085' || ('\u00A0' <= ch && ch <= '\uD7FF') || ('\uE000' <= ch && ch <= '\uFFFD'))
+ && (ch != '\uFEFF')) {
+ // unicode is used
+ if (!this.allowUnicode) {
+ specialCharacters = true;
+ }
+ } else {
+ specialCharacters = true;
+ }
+ }
+ // Detect important whitespace combinations.
+ if (ch == ' ') {
+ if (index == 0) {
+ leadingSpace = true;
+ }
+ if (index == scalar.length() - 1) {
+ trailingSpace = true;
+ }
+ if (previousBreak) {
+ breakSpace = true;
+ }
+ previousSpace = true;
+ previousBreak = false;
+ } else if ("\n\u0085\u2028\u2029".indexOf(ch) != -1) {
+ if (index == 0) {
+ leadingBreak = true;
+ }
+ if (index == scalar.length() - 1) {
+ trailingBreak = true;
+ }
+ if (previousSpace) {
+ spaceBreak = true;
+ }
+ previousSpace = false;
+ previousBreak = true;
+ } else {
+ previousSpace = false;
+ previousBreak = false;
+ }
+
+ // Prepare for the next character.
+ index++;
+ preceededByWhitespace = "\0 \t\r\n\u0085\u2028\u2029".indexOf(ch) != -1;
+ followedByWhitespace = (index + 1 >= scalar.length() || "\0 \t\r\n\u0085\u2028\u2029"
+ .indexOf(scalar.charAt(index + 1)) != -1);
+ }
+ // Let's decide what styles are allowed.
+ boolean allowFlowPlain = true;
+ boolean allowBlockPlain = true;
+ boolean allowSingleQuoted = true;
+ boolean allowDoubleQuoted = true;
+ boolean allowBlock = true;
+ // Leading and trailing whitespaces are bad for plain scalars.
+ if (leadingSpace || leadingBreak || trailingSpace || trailingBreak) {
+ allowFlowPlain = allowBlockPlain = false;
+ }
+ // We do not permit trailing spaces for block scalars.
+ if (trailingSpace) {
+ allowBlock = false;
+ }
+ // Spaces at the beginning of a new line are only acceptable for block
+ // scalars.
+ if (breakSpace) {
+ allowFlowPlain = allowBlockPlain = allowSingleQuoted = false;
+ }
+ // Spaces followed by breaks, as well as special character are only
+ // allowed for double quoted scalars.
+ if (spaceBreak || specialCharacters) {
+ allowFlowPlain = allowBlockPlain = allowSingleQuoted = allowBlock = false;
+ }
+ // Although the plain scalar writer supports breaks, we never emit
+ // multiline plain scalars.
+ if (lineBreaks) {
+ allowFlowPlain = allowBlockPlain = false;
+ }
+ // Flow indicators are forbidden for flow plain scalars.
+ if (flowIndicators) {
+ allowFlowPlain = false;
+ }
+ // Block indicators are forbidden for block plain scalars.
+ if (blockIndicators) {
+ allowBlockPlain = false;
+ }
+
+ return new ScalarAnalysis(scalar, false, lineBreaks, allowFlowPlain, allowBlockPlain,
+ allowSingleQuoted, allowDoubleQuoted, allowBlock);
+ }
+
+ // Writers.
+
+ void flushStream() throws IOException {
+ stream.flush();
+ }
+
+ void writeStreamStart() {
+ // BOM is written by Writer.
+ }
+
+ void writeStreamEnd() throws IOException {
+ flushStream();
+ }
+
+ void writeIndicator(String indicator, boolean needWhitespace, boolean whitespace,
+ boolean indentation) throws IOException {
+ String data = null;
+ if (this.whitespace || !needWhitespace) {
+ data = indicator;
+ } else {
+ data = " " + indicator;
+ }
+ this.whitespace = whitespace;
+ this.indention = this.indention && indentation;
+ this.column += data.length();
+ openEnded = false;
+ stream.write(data);
+ }
+
+ void writeIndent() throws IOException {
+ int indent;
+ if (this.indent != null) {
+ indent = this.indent;
+ } else {
+ indent = 0;
+ }
+
+ if (!this.indention || this.column > indent || (this.column == indent && !this.whitespace)) {
+ writeLineBreak(null);
+ }
+
+ if (this.column < indent) {
+ this.whitespace = true;
+ StringBuffer data = new StringBuffer();
+ for (int i = 0; i < indent - this.column; i++) {
+ data.append(" ");
+ }
+ this.column = indent;
+ stream.write(data.toString());
+ }
+ }
+
+ private void writeLineBreak(String data) throws IOException {
+ if (data == null) {
+ data = this.bestLineBreak;
+ }
+ this.whitespace = true;
+ this.indention = true;
+ this.line++;
+ this.column = 0;
+ stream.write(data);
+ }
+
+ void writeVersionDirective(String versionText) throws IOException {
+ stream.write("%YAML " + versionText);
+ writeLineBreak(null);
+ }
+
+ void writeTagDirective(String handleText, String prefixText) throws IOException {
+ stream.write("%TAG " + handleText + " " + prefixText);
+ writeLineBreak(null);
+ }
+
+ // Scalar streams.
+ private void writeSingleQuoted(String text, boolean split) throws IOException {
+ writeIndicator("'", true, false, false);
+ boolean spaces = false;
+ boolean breaks = false;
+ int start = 0, end = 0;
+ char ch;
+ while (end <= text.length()) {
+ ch = 0;
+ if (end < text.length()) {
+ ch = text.charAt(end);
+ }
+ if (spaces) {
+ if (ch == 0 || ch != ' ') {
+ if (start + 1 == end && this.column > this.bestWidth && split && start != 0
+ && end != text.length()) {
+ writeIndent();
+ } else {
+ String data = text.substring(start, end);
+ this.column += data.length();
+ stream.write(data);
+ }
+ start = end;
+ }
+ } else if (breaks) {
+ if (ch == 0 || "\n\u0085\u2028\u2029".indexOf(ch) == -1) {
+ if (text.charAt(start) == '\n') {
+ writeLineBreak(null);
+ }
+ String data = text.substring(start, end);
+ for (char br : data.toCharArray()) {
+ if (br == '\n') {
+ writeLineBreak(null);
+ } else {
+ writeLineBreak(String.valueOf(br));
+ }
+ }
+ writeIndent();
+ start = end;
+ }
+ } else {
+ if (ch == 0 || " \n\u0085\u2028\u2029".indexOf(ch) != -1 || ch == '\'') {
+ if (start < end) {
+ String data = text.substring(start, end);
+ this.column += data.length();
+ stream.write(data);
+ start = end;
+ }
+ }
+ }
+ if (ch == '\'') {
+ String data = "''";
+ this.column += 2;
+ stream.write(data);
+ start = end + 1;
+ }
+ if (ch != 0) {
+ spaces = ch == ' ';
+ breaks = "\n\u0085\u2028\u2029".indexOf(ch) != -1;
+ }
+ end++;
+ }
+ writeIndicator("'", false, false, false);
+ }
+
+ private void writeDoubleQuoted(String text, boolean split) throws IOException {
+ writeIndicator("\"", true, false, false);
+ int start = 0;
+ int end = 0;
+ while (end <= text.length()) {
+ Character ch = null;
+ if (end < text.length()) {
+ ch = text.charAt(end);
+ }
+ if (ch == null || "\"\\\u0085\u2028\u2029\uFEFF".indexOf(ch) != -1
+ || !('\u0020' <= ch && ch <= '\u007E')) {
+ if (start < end) {
+ String data = text.substring(start, end);
+ this.column += data.length();
+ stream.write(data);
+ start = end;
+ }
+ if (ch != null) {
+ String data;
+ if (ESCAPE_REPLACEMENTS.containsKey(new Character(ch))) {
+ data = "\\" + ESCAPE_REPLACEMENTS.get(new Character(ch));
+ } else if (ch <= '\u00FF') {
+ String s = "0" + Integer.toString(ch, 16);
+ data = "\\x" + s.substring(s.length() - 2);
+ } else {
+ String s = "000" + Integer.toString(ch, 16);
+ data = "\\u" + s.substring(s.length() - 4);
+ }
+ this.column += data.length();
+ stream.write(data);
+ start = end + 1;
+ }
+ }
+ if ((0 < end && end < (text.length() - 1)) && (ch == ' ' || start >= end)
+ && (this.column + (end - start)) > this.bestWidth && split) {
+ String data;
+ if (start >= end) {
+ data = "\\";
+ } else {
+ data = text.substring(start, end) + "\\";
+ }
+ if (start < end) {
+ start = end;
+ }
+ this.column += data.length();
+ stream.write(data);
+ writeIndent();
+ this.whitespace = false;
+ this.indention = false;
+ if (text.charAt(start) == ' ') {
+ data = "\\";
+ this.column += data.length();
+ stream.write(data);
+ }
+ }
+ end += 1;
+ }
+ writeIndicator("\"", false, false, false);
+ }
+
+ private String determineBlockHints(String text) {
+ StringBuffer hints = new StringBuffer();
+ if (text != null && text.length() > 0) {
+ if (" \n\u0085\u2028\u2029".indexOf(text.charAt(0)) != -1) {
+ hints.append(bestIndent);
+ }
+ char ch1 = text.charAt(text.length() - 1);
+ if ("\n\u0085\u2028\u2029".indexOf(ch1) == -1) {
+ hints.append("-");
+ } else if (text.length() == 1
+ || ("\n\u0085\u2028\u2029".indexOf(text.charAt(text.length() - 2)) != -1)) {
+ hints.append("+");
+ }
+ }
+ return hints.toString();
+ }
+
+ void writeFolded(String text) throws IOException {
+ String hints = determineBlockHints(text);
+ writeIndicator(">" + hints, true, false, false);
+ if (hints.length() > 0 && (hints.charAt(hints.length() - 1) == '+')) {
+ openEnded = true;
+ }
+ writeLineBreak(null);
+ boolean leadingSpace = true;
+ boolean spaces = false;
+ boolean breaks = true;
+ int start = 0, end = 0;
+ while (end <= text.length()) {
+ char ch = 0;
+ if (end < text.length()) {
+ ch = text.charAt(end);
+ }
+ if (breaks) {
+ if (ch == 0 || ("\n\0085\u2028\u2029".indexOf(ch) == -1)) {
+ if (!leadingSpace && ch != 0 && ch != ' ' && text.charAt(start) == '\n') {
+ writeLineBreak(null);
+ }
+ leadingSpace = (ch == ' ');
+ String data = text.substring(start, end);
+ for (char br : data.toCharArray()) {
+ if (br == '\n') {
+ writeLineBreak(null);
+ } else {
+ writeLineBreak(String.valueOf(br));
+ }
+ }
+ if (ch != 0) {
+ writeIndent();
+ }
+ start = end;
+ }
+ } else if (spaces) {
+ if (ch != ' ') {
+ if (start + 1 == end && this.column > this.bestWidth) {
+ writeIndent();
+ } else {
+ String data = text.substring(start, end);
+ this.column += data.length();
+ stream.write(data);
+ }
+ start = end;
+ }
+ } else {
+ if (ch == 0 || " \n\0085\u2028\u2029".indexOf(ch) != -1) {
+ String data = text.substring(start, end);
+ stream.write(data);
+ if (ch == 0) {
+ writeLineBreak(null);
+ }
+ start = end;
+ }
+ }
+ if (ch != 0) {
+ breaks = ("\n\u0085\u2028\u2029".indexOf(ch) != -1);
+ spaces = (ch == ' ');
+ }
+ end++;
+ }
+ }
+
+ void writeLiteral(String text) throws IOException {
+ String hints = determineBlockHints(text);
+ writeIndicator("|" + hints, true, false, false);
+ if (hints.length() > 0 && (hints.charAt(hints.length() - 1)) == '+') {
+ openEnded = true;
+ }
+ writeLineBreak(null);
+ boolean breaks = true;
+ int start = 0, end = 0;
+ while (end <= text.length()) {
+ char ch = 0;
+ if (end < text.length()) {
+ ch = text.charAt(end);
+ }
+ if (breaks) {
+ if (ch == 0 || "\n\u0085\u2028\u2029".indexOf(ch) == -1) {
+ String data = text.substring(start, end);
+ for (char br : data.toCharArray()) {
+ if (br == '\n') {
+ writeLineBreak(null);
+ } else {
+ writeLineBreak(String.valueOf(br));
+ }
+ }
+ if (ch != 0) {
+ writeIndent();
+ }
+ start = end;
+ }
+ } else {
+ if (ch == 0 || "\n\u0085\u2028\u2029".indexOf(ch) != -1) {
+ String data = text.substring(start, end);
+ stream.write(data);
+ if (ch == 0) {
+ writeLineBreak(null);
+ }
+ start = end;
+ }
+ }
+ if (ch != 0) {
+ breaks = ("\n\u0085\u2028\u2029".indexOf(ch) != -1);
+ }
+ end++;
+ }
+ }
+
+ void writePlain(String text, boolean split) throws IOException {
+ if (rootContext) {
+ openEnded = true;
+ }
+ if (text == null || "".equals(text)) {
+ return;
+ }
+ if (!this.whitespace) {
+ String data = " ";
+ this.column += data.length();
+ stream.write(data);
+ }
+ this.whitespace = false;
+ this.indention = false;
+ boolean spaces = false;
+ boolean breaks = false;
+ int start = 0, end = 0;
+ while (end <= text.length()) {
+ char ch = 0;
+ if (end < text.length()) {
+ ch = text.charAt(end);
+ }
+ if (spaces) {
+ if (ch != ' ') {
+ if (start + 1 == end && this.column > this.bestWidth && split) {
+ writeIndent();
+ this.whitespace = false;
+ this.indention = false;
+ } else {
+ String data = text.substring(start, end);
+ this.column += data.length();
+ stream.write(data);
+ }
+ start = end;
+ }
+ } else if (breaks) {
+ if ("\n\u0085\u2028\u2029".indexOf(ch) == -1) {
+ if (text.charAt(start) == '\n') {
+ writeLineBreak(null);
+ }
+ String data = text.substring(start, end);
+ for (char br : data.toCharArray()) {
+ if (br == '\n') {
+ writeLineBreak(null);
+ } else {
+ writeLineBreak(String.valueOf(br));
+ }
+ }
+ writeIndent();
+ this.whitespace = false;
+ this.indention = false;
+ start = end;
+ }
+ } else {
+ if (ch == 0 || "\n\u0085\u2028\u2029".indexOf(ch) != -1) {
+ String data = text.substring(start, end);
+ this.column += data.length();
+ stream.write(data);
+ start = end;
+ }
+ }
+ if (ch != 0) {
+ spaces = (ch == ' ');
+ breaks = ("\n\u0085\u2028\u2029".indexOf(ch) != -1);
+ }
+ end++;
+ }
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/emitter/EmitterException.java b/src/main/java/org/yaml/snakeyaml/emitter/EmitterException.java
new file mode 100644
index 00000000..b63e0c4e
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/emitter/EmitterException.java
@@ -0,0 +1,17 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.emitter;
+
+import org.yaml.snakeyaml.error.YAMLException;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public class EmitterException extends YAMLException {
+ private static final long serialVersionUID = -8280070025452995908L;
+
+ public EmitterException(String msg) {
+ super(msg);
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/emitter/EmitterState.java b/src/main/java/org/yaml/snakeyaml/emitter/EmitterState.java
new file mode 100755
index 00000000..e7667fb5
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/emitter/EmitterState.java
@@ -0,0 +1,15 @@
+/**
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.emitter;
+
+import java.io.IOException;
+
+/**
+ * Python's methods are first class object. Java needs a class.
+ *
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+interface EmitterState {
+ void expect() throws IOException;
+} \ No newline at end of file
diff --git a/src/main/java/org/yaml/snakeyaml/emitter/ScalarAnalysis.java b/src/main/java/org/yaml/snakeyaml/emitter/ScalarAnalysis.java
new file mode 100644
index 00000000..61ea599b
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/emitter/ScalarAnalysis.java
@@ -0,0 +1,31 @@
+/**
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.emitter;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+final class ScalarAnalysis {
+ public String scalar;
+ public boolean empty;
+ public boolean multiline;
+ public boolean allowFlowPlain;
+ public boolean allowBlockPlain;
+ public boolean allowSingleQuoted;
+ public boolean allowDoubleQuoted;
+ public boolean allowBlock;
+
+ public ScalarAnalysis(String scalar, boolean empty, boolean multiline, boolean allowFlowPlain,
+ boolean allowBlockPlain, boolean allowSingleQuoted, boolean allowDoubleQuoted,
+ boolean allowBlock) {
+ this.scalar = scalar;
+ this.empty = empty;
+ this.multiline = multiline;
+ this.allowFlowPlain = allowFlowPlain;
+ this.allowBlockPlain = allowBlockPlain;
+ this.allowSingleQuoted = allowSingleQuoted;
+ this.allowDoubleQuoted = allowDoubleQuoted;
+ this.allowBlock = allowBlock;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/yaml/snakeyaml/error/Mark.java b/src/main/java/org/yaml/snakeyaml/error/Mark.java
new file mode 100644
index 00000000..d8341f7a
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/error/Mark.java
@@ -0,0 +1,107 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.error;
+
+import org.yaml.snakeyaml.scanner.ScannerImpl;
+
+/**
+ * It's just a record and its only use is producing nice error messages. Parser
+ * does not use it for any other purposes.
+ *
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public final class Mark {
+ private String name;
+ private int line;
+ private int column;
+ private String buffer;
+ private int pointer;
+
+ public Mark(String name, int index, int line, int column, String buffer, int pointer) {
+ super();
+ this.name = name;
+ this.line = line;
+ this.column = column;
+ this.buffer = buffer;
+ this.pointer = pointer;
+ }
+
+ private boolean isLineBreak(char ch) {
+ return ScannerImpl.NULL_OR_LINEBR.indexOf(ch) != -1;
+ }
+
+ public String get_snippet(int indent, int max_length) {
+ if (buffer == null) {
+ return null;
+ }
+ float half = max_length / 2 - 1;
+ int start = pointer;
+ String head = "";
+ while ((start > 0) && (!isLineBreak(buffer.charAt(start - 1)))) {
+ start -= 1;
+ if (pointer - start > half) {
+ head = " ... ";
+ start += 5;
+ break;
+ }
+ }
+ String tail = "";
+ int end = pointer;
+ while ((end < buffer.length()) && (!isLineBreak(buffer.charAt(end)))) {
+ end += 1;
+ if (end - pointer > half) {
+ tail = " ... ";
+ end -= 5;
+ break;
+ }
+ }
+ String snippet = buffer.substring(start, end);
+ StringBuffer result = new StringBuffer();
+ for (int i = 0; i < indent; i++) {
+ result.append(" ");
+ }
+ result.append(head);
+ result.append(snippet);
+ result.append(tail);
+ result.append("\n");
+ for (int i = 0; i < indent + pointer - start + head.length(); i++) {
+ result.append(" ");
+ }
+ result.append("^");
+ return result.toString();
+ }
+
+ public String get_snippet() {
+ return get_snippet(4, 75);
+ }
+
+ @Override
+ public String toString() {
+ String snippet = get_snippet();
+ StringBuffer where = new StringBuffer(" in \"");
+ where.append(name);
+ where.append("\", line ");
+ where.append(line);
+ where.append(", column ");
+ where.append(column);
+ if (snippet != null) {
+ where.append(":\n");
+ where.append(snippet);
+ }
+ return where.toString();
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public int getLine() {
+ return line;
+ }
+
+ public int getColumn() {
+ return column;
+ }
+
+}
diff --git a/src/main/java/org/yaml/snakeyaml/error/MarkedYAMLException.java b/src/main/java/org/yaml/snakeyaml/error/MarkedYAMLException.java
new file mode 100644
index 00000000..aff6dcc5
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/error/MarkedYAMLException.java
@@ -0,0 +1,61 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.error;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public class MarkedYAMLException extends YAMLException {
+
+ private static final long serialVersionUID = -9119388488683035101L;
+ private String context;
+ private Mark contextMark;
+ private String problem;
+ private Mark problemMark;
+ private String note;
+
+ protected MarkedYAMLException(String context, Mark contextMark, String problem,
+ Mark problemMark, String note) {
+ super(context + "; " + problem);
+ this.context = context;
+ this.contextMark = contextMark;
+ this.problem = problem;
+ this.problemMark = problemMark;
+ this.note = note;
+ }
+
+ protected MarkedYAMLException(String context, Mark contextMark, String problem, Mark problemMark) {
+ this(context, contextMark, problem, problemMark, null);
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer lines = new StringBuffer();
+ if (context != null) {
+ lines.append(context);
+ lines.append("\n");
+ }
+ if (contextMark != null
+ && (problem == null || problemMark == null
+ || (contextMark.getName() != problemMark.getName())
+ || (contextMark.getLine() != problemMark.getLine()) || (contextMark
+ .getColumn() != problemMark.getColumn()))) {
+ lines.append(contextMark.toString());
+ lines.append("\n");
+ }
+ if (problem != null) {
+ lines.append(problem);
+ lines.append("\n");
+ }
+ if (problemMark != null) {
+ lines.append(problemMark.toString());
+ lines.append("\n");
+ }
+ if (note != null) {
+ lines.append(note);
+ lines.append("\n");
+ }
+ return lines.toString();
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/error/YAMLException.java b/src/main/java/org/yaml/snakeyaml/error/YAMLException.java
new file mode 100644
index 00000000..4a90a987
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/error/YAMLException.java
@@ -0,0 +1,19 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.error;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public class YAMLException extends RuntimeException {
+ private static final long serialVersionUID = -4738336175050337570L;
+
+ public YAMLException(String message) {
+ super(message);
+ }
+
+ public YAMLException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/events/AliasEvent.java b/src/main/java/org/yaml/snakeyaml/events/AliasEvent.java
new file mode 100644
index 00000000..431580cb
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/events/AliasEvent.java
@@ -0,0 +1,15 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.events;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public final class AliasEvent extends NodeEvent {
+ public AliasEvent(String anchor, Mark startMark, Mark endMark) {
+ super(anchor, startMark, endMark);
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/events/CollectionEndEvent.java b/src/main/java/org/yaml/snakeyaml/events/CollectionEndEvent.java
new file mode 100644
index 00000000..283db3b6
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/events/CollectionEndEvent.java
@@ -0,0 +1,16 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.events;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public abstract class CollectionEndEvent extends Event {
+
+ public CollectionEndEvent(Mark startMark, Mark endMark) {
+ super(startMark, endMark);
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/events/CollectionStartEvent.java b/src/main/java/org/yaml/snakeyaml/events/CollectionStartEvent.java
new file mode 100644
index 00000000..19d5dc47
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/events/CollectionStartEvent.java
@@ -0,0 +1,40 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.events;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public abstract class CollectionStartEvent extends NodeEvent {
+ private final String tag;
+ private final boolean implicit;
+ private final Boolean flowStyle;
+
+ public CollectionStartEvent(String anchor, String tag, boolean implicit, Mark startMark,
+ Mark endMark, Boolean flowStyle) {
+ super(anchor, startMark, endMark);
+ this.tag = tag;
+ this.implicit = implicit;
+ this.flowStyle = flowStyle;
+ }
+
+ public String getTag() {
+ return this.tag;
+ }
+
+ public boolean getImplicit() {
+ return this.implicit;
+ }
+
+ public Boolean getFlowStyle() {
+ return this.flowStyle;
+ }
+
+ @Override
+ protected String getArguments() {
+ return super.getArguments() + ", tag=" + tag + ", implicit=" + implicit;
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/events/DocumentEndEvent.java b/src/main/java/org/yaml/snakeyaml/events/DocumentEndEvent.java
new file mode 100644
index 00000000..fff13b97
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/events/DocumentEndEvent.java
@@ -0,0 +1,22 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.events;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public final class DocumentEndEvent extends Event {
+ private final boolean explicit;
+
+ public DocumentEndEvent(Mark startMark, Mark endMark, boolean explicit) {
+ super(startMark, endMark);
+ this.explicit = explicit;
+ }
+
+ public boolean getExplicit() {
+ return explicit;
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/events/DocumentStartEvent.java b/src/main/java/org/yaml/snakeyaml/events/DocumentStartEvent.java
new file mode 100644
index 00000000..051661f4
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/events/DocumentStartEvent.java
@@ -0,0 +1,37 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.events;
+
+import java.util.Map;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public final class DocumentStartEvent extends Event {
+ private final boolean explicit;
+ private final Integer[] version;
+ private final Map<String, String> tags;
+
+ public DocumentStartEvent(Mark startMark, Mark endMark, boolean explicit, Integer[] version,
+ Map<String, String> tags) {
+ super(startMark, endMark);
+ this.explicit = explicit;
+ this.version = version;
+ this.tags = tags;
+ }
+
+ public boolean getExplicit() {
+ return explicit;
+ }
+
+ public Integer[] getVersion() {
+ return version;
+ }
+
+ public Map<String, String> getTags() {
+ return tags;
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/events/Event.java b/src/main/java/org/yaml/snakeyaml/events/Event.java
new file mode 100644
index 00000000..858793bd
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/events/Event.java
@@ -0,0 +1,51 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.events;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public abstract class Event {
+ private final Mark startMark;
+ private final Mark endMark;
+
+ public Event(Mark startMark, Mark endMark) {
+ this.startMark = startMark;
+ this.endMark = endMark;
+ }
+
+ public String toString() {
+ return "<" + this.getClass().getName() + "(" + getArguments() + ")>";
+ }
+
+ public Mark getStartMark() {
+ return startMark;
+ }
+
+ public Mark getEndMark() {
+ return endMark;
+ }
+
+ /**
+ * @see __repr__ for Event in PyYAML
+ */
+ protected String getArguments() {
+ return "";
+ }
+
+ /*
+ * for tests only
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof Event) {
+ return toString().equals(obj.toString());
+ } else {
+ return false;
+ }
+ }
+
+}
diff --git a/src/main/java/org/yaml/snakeyaml/events/MappingEndEvent.java b/src/main/java/org/yaml/snakeyaml/events/MappingEndEvent.java
new file mode 100644
index 00000000..f90bba36
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/events/MappingEndEvent.java
@@ -0,0 +1,16 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.events;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public final class MappingEndEvent extends CollectionEndEvent {
+
+ public MappingEndEvent(Mark startMark, Mark endMark) {
+ super(startMark, endMark);
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/events/MappingStartEvent.java b/src/main/java/org/yaml/snakeyaml/events/MappingStartEvent.java
new file mode 100644
index 00000000..97cb7aaf
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/events/MappingStartEvent.java
@@ -0,0 +1,16 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.events;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public final class MappingStartEvent extends CollectionStartEvent {
+ public MappingStartEvent(String anchor, String tag, boolean implicit, Mark startMark,
+ Mark endMark, Boolean flowStyle) {
+ super(anchor, tag, implicit, startMark, endMark, flowStyle);
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/events/NodeEvent.java b/src/main/java/org/yaml/snakeyaml/events/NodeEvent.java
new file mode 100644
index 00000000..5c31d958
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/events/NodeEvent.java
@@ -0,0 +1,28 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.events;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public abstract class NodeEvent extends Event {
+
+ private final String anchor;
+
+ public NodeEvent(String anchor, Mark startMark, Mark endMark) {
+ super(startMark, endMark);
+ this.anchor = anchor;
+ }
+
+ public String getAnchor() {
+ return this.anchor;
+ }
+
+ @Override
+ protected String getArguments() {
+ return "anchor=" + anchor;
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/events/ScalarEvent.java b/src/main/java/org/yaml/snakeyaml/events/ScalarEvent.java
new file mode 100644
index 00000000..b76d9b7f
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/events/ScalarEvent.java
@@ -0,0 +1,48 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.events;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public final class ScalarEvent extends NodeEvent {
+ private final String tag;
+ private final Character style;
+ private final String value;
+ private final boolean[] implicit;
+
+ public ScalarEvent(String anchor, String tag, boolean[] implicit, String value, Mark startMark,
+ Mark endMark, Character style) {
+ super(anchor, startMark, endMark);
+ this.tag = tag;
+ this.implicit = implicit;
+ this.value = value;
+ this.style = style;
+ }
+
+ public String getTag() {
+ return this.tag;
+ }
+
+ public Character getStyle() {
+ return this.style;
+ }
+
+ public String getValue() {
+ return this.value;
+ }
+
+ public boolean[] getImplicit() {
+ return this.implicit;
+ }
+
+ @Override
+ protected String getArguments() {
+ return super.getArguments() + ", tag=" + tag + ", implicit=[" + implicit[0] + ", "
+ + implicit[1] + "], value=" + value;
+ }
+
+}
diff --git a/src/main/java/org/yaml/snakeyaml/events/SequenceEndEvent.java b/src/main/java/org/yaml/snakeyaml/events/SequenceEndEvent.java
new file mode 100644
index 00000000..e98552d9
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/events/SequenceEndEvent.java
@@ -0,0 +1,16 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.events;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public final class SequenceEndEvent extends CollectionEndEvent {
+
+ public SequenceEndEvent(Mark startMark, Mark endMark) {
+ super(startMark, endMark);
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/events/SequenceStartEvent.java b/src/main/java/org/yaml/snakeyaml/events/SequenceStartEvent.java
new file mode 100644
index 00000000..769d6137
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/events/SequenceStartEvent.java
@@ -0,0 +1,16 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.events;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public final class SequenceStartEvent extends CollectionStartEvent {
+ public SequenceStartEvent(String anchor, String tag, boolean implicit, Mark startMark,
+ Mark endMark, Boolean flowStyle) {
+ super(anchor, tag, implicit, startMark, endMark, flowStyle);
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/events/StreamEndEvent.java b/src/main/java/org/yaml/snakeyaml/events/StreamEndEvent.java
new file mode 100644
index 00000000..861a6129
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/events/StreamEndEvent.java
@@ -0,0 +1,15 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.events;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public final class StreamEndEvent extends Event {
+ public StreamEndEvent(Mark startMark, Mark endMark) {
+ super(startMark, endMark);
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/events/StreamStartEvent.java b/src/main/java/org/yaml/snakeyaml/events/StreamStartEvent.java
new file mode 100644
index 00000000..3a7ee20c
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/events/StreamStartEvent.java
@@ -0,0 +1,16 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.events;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public final class StreamStartEvent extends Event {
+
+ public StreamStartEvent(Mark startMark, Mark endMark) {
+ super(startMark, endMark);
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/introspector/FieldProperty.java b/src/main/java/org/yaml/snakeyaml/introspector/FieldProperty.java
new file mode 100644
index 00000000..6faa0955
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/introspector/FieldProperty.java
@@ -0,0 +1,32 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.introspector;
+
+import java.lang.reflect.Field;
+
+import org.yaml.snakeyaml.error.YAMLException;
+
+public class FieldProperty extends Property {
+ private final Field field;
+
+ public FieldProperty(Field field) {
+ super(field.getName(), field.getType());
+ this.field = field;
+ }
+
+ @Override
+ public void set(Object object, Object value) throws Exception {
+ field.set(object, value);
+ }
+
+ @Override
+ public Object get(Object object) {
+ try {
+ return field.get(object);
+ } catch (Exception e) {
+ throw new YAMLException("Unable to access field " + field.getName() + " on object "
+ + object + " : " + e);
+ }
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/yaml/snakeyaml/introspector/MethodProperty.java b/src/main/java/org/yaml/snakeyaml/introspector/MethodProperty.java
new file mode 100644
index 00000000..5a4c3922
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/introspector/MethodProperty.java
@@ -0,0 +1,32 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.introspector;
+
+import java.beans.PropertyDescriptor;
+
+import org.yaml.snakeyaml.error.YAMLException;
+
+public class MethodProperty extends Property {
+ private final PropertyDescriptor property;
+
+ public MethodProperty(PropertyDescriptor property) {
+ super(property.getName(), property.getPropertyType());
+ this.property = property;
+ }
+
+ @Override
+ public void set(Object object, Object value) throws Exception {
+ property.getWriteMethod().invoke(object, value);
+ }
+
+ @Override
+ public Object get(Object object) {
+ try {
+ return property.getReadMethod().invoke(object);
+ } catch (Exception e) {
+ throw new YAMLException("Unable to find getter for property " + property.getName()
+ + " on object " + object + ":" + e);
+ }
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/yaml/snakeyaml/introspector/Property.java b/src/main/java/org/yaml/snakeyaml/introspector/Property.java
new file mode 100644
index 00000000..c815b0a0
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/introspector/Property.java
@@ -0,0 +1,35 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.introspector;
+
+public abstract class Property implements Comparable<Property> {
+ private final String name;
+ private final Class<? extends Object> type;
+
+ public Property(String name, Class<? extends Object> type) {
+ this.name = name;
+ this.type = type;
+ }
+
+ public Class<? extends Object> getType() {
+ return type;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String toString() {
+ return getName() + " of " + getType();
+ }
+
+ public int compareTo(Property o) {
+ return name.compareTo(o.name);
+ }
+
+ abstract public void set(Object object, Object value) throws Exception;
+
+ abstract public Object get(Object object);
+} \ No newline at end of file
diff --git a/src/main/java/org/yaml/snakeyaml/nodes/CollectionNode.java b/src/main/java/org/yaml/snakeyaml/nodes/CollectionNode.java
new file mode 100644
index 00000000..b414b10d
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/nodes/CollectionNode.java
@@ -0,0 +1,30 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.nodes;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public abstract class CollectionNode extends Node {
+ private Boolean flowStyle;
+
+ public CollectionNode(String tag, Object value, Mark startMark, Mark endMark, Boolean flowStyle) {
+ super(tag, value, startMark, endMark);
+ this.flowStyle = flowStyle;
+ }
+
+ public Boolean getFlowStyle() {
+ return flowStyle;
+ }
+
+ public void setFlowStyle(Boolean flowStyle) {
+ this.flowStyle = flowStyle;
+ }
+
+ public void setEndMark(Mark endMark) {
+ this.endMark = endMark;
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/nodes/MappingNode.java b/src/main/java/org/yaml/snakeyaml/nodes/MappingNode.java
new file mode 100644
index 00000000..b3e233cd
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/nodes/MappingNode.java
@@ -0,0 +1,71 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.nodes;
+
+import java.util.List;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public class MappingNode extends CollectionNode {
+ private Class<? extends Object> keyType;
+ private Class<? extends Object> valueType;
+
+ public MappingNode(String tag, List<Node[]> value, Mark startMark, Mark endMark,
+ Boolean flowStyle) {
+ super(tag, value, startMark, endMark, flowStyle);
+ keyType = Object.class;
+ valueType = Object.class;
+ }
+
+ public MappingNode(String tag, List<Node[]> value, Boolean flowStyle) {
+ super(tag, value, null, null, flowStyle);
+ }
+
+ @Override
+ public NodeId getNodeId() {
+ return NodeId.mapping;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public List<Node[]> getValue() {
+ List<Node[]> mapping = (List<Node[]>) super.getValue();
+ for (Node[] nodes : mapping) {
+ nodes[0].setType(keyType);
+ nodes[1].setType(valueType);
+ }
+ return mapping;
+ }
+
+ public void setValue(List<Node[]> merge) {
+ value = merge;
+ }
+
+ public void setKeyType(Class<? extends Object> keyType) {
+ this.keyType = keyType;
+ }
+
+ public void setValueType(Class<? extends Object> valueType) {
+ this.valueType = valueType;
+ }
+
+ @Override
+ public String toString() {
+ String values;
+ StringBuffer buf = new StringBuffer();
+ for (Node[] node : getValue()) {
+ buf.append("{ key=");
+ buf.append(node[0]);
+ buf.append("; value=");
+ // to avoid overflow in case of recursive structures
+ buf.append(System.identityHashCode(node[1]));
+ buf.append(" }");
+ }
+ values = buf.toString();
+ return "<" + this.getClass().getName() + " (tag=" + getTag() + ", values=" + values + ")>";
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/nodes/Node.java b/src/main/java/org/yaml/snakeyaml/nodes/Node.java
new file mode 100644
index 00000000..69cbbf3a
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/nodes/Node.java
@@ -0,0 +1,76 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.nodes;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public abstract class Node {
+ private String tag;
+ protected Object value;
+ private Mark startMark;
+ protected Mark endMark;
+ private Class<? extends Object> type;
+
+ public Node(String tag, Object value, Mark startMark, Mark endMark) {
+ setTag(tag);
+ if (value == null) {
+ throw new NullPointerException("value in a Node is required.");
+ }
+ this.value = value;
+ this.startMark = startMark;
+ this.endMark = endMark;
+ this.type = Object.class;
+ }
+
+ public String getTag() {
+ return this.tag;
+ }
+
+ public Object getValue() {
+ return this.value;
+ }
+
+ public String toString() {
+ return "<" + this.getClass().getName() + " (tag=" + getTag() + ", value=" + getValue()
+ + ")>";
+ }
+
+ /**
+ * For error reporting.
+ *
+ * @see class variable 'id' in PyYAML
+ * @return scalar, sequence, mapping
+ */
+ public abstract NodeId getNodeId();
+
+ public Mark getStartMark() {
+ return startMark;
+ }
+
+ public void setTag(String tag) {
+ if (tag == null) {
+ throw new NullPointerException("tag in a Node is required.");
+ }
+ this.tag = tag;
+ }
+
+ /*
+ * It is not allowed to overwrite this method. Two Nodes are never equal.
+ */
+ @Override
+ public final boolean equals(Object obj) {
+ return super.equals(obj);
+ }
+
+ public Class<? extends Object> getType() {
+ return type;
+ }
+
+ public void setType(Class<? extends Object> type) {
+ this.type = type;
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/nodes/NodeId.java b/src/main/java/org/yaml/snakeyaml/nodes/NodeId.java
new file mode 100644
index 00000000..956114c1
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/nodes/NodeId.java
@@ -0,0 +1,8 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.nodes;
+
+public enum NodeId {
+ scalar, sequence, mapping;
+}
diff --git a/src/main/java/org/yaml/snakeyaml/nodes/ScalarNode.java b/src/main/java/org/yaml/snakeyaml/nodes/ScalarNode.java
new file mode 100644
index 00000000..b7bb544e
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/nodes/ScalarNode.java
@@ -0,0 +1,27 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.nodes;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public class ScalarNode extends Node {
+ private Character style;
+
+ public ScalarNode(String tag, String value, Mark startMark, Mark endMark, Character style) {
+ super(tag, value, startMark, endMark);
+ this.style = style;
+ }
+
+ public Character getStyle() {
+ return style;
+ }
+
+ @Override
+ public NodeId getNodeId() {
+ return NodeId.scalar;
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/nodes/SequenceNode.java b/src/main/java/org/yaml/snakeyaml/nodes/SequenceNode.java
new file mode 100644
index 00000000..48914174
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/nodes/SequenceNode.java
@@ -0,0 +1,43 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.nodes;
+
+import java.util.List;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public class SequenceNode extends CollectionNode {
+ private Class<? extends Object> listType;
+
+ public SequenceNode(String tag, List<Node> value, Mark startMark, Mark endMark,
+ Boolean flowStyle) {
+ super(tag, value, startMark, endMark, flowStyle);
+ listType = Object.class;
+ }
+
+ public SequenceNode(String tag, List<Node> value, Boolean flowStyle) {
+ this(tag, value, null, null, flowStyle);
+ }
+
+ @Override
+ public NodeId getNodeId() {
+ return NodeId.sequence;
+ }
+
+ @SuppressWarnings("unchecked")
+ public List<Node> getValue() {
+ List<Node> value = (List<Node>) super.getValue();
+ for (Node node : value) {
+ node.setType(listType);
+ }
+ return value;
+ }
+
+ public void setListType(Class<? extends Object> listType) {
+ this.listType = listType;
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/parser/Parser.java b/src/main/java/org/yaml/snakeyaml/parser/Parser.java
new file mode 100644
index 00000000..6564de0b
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/parser/Parser.java
@@ -0,0 +1,22 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.parser;
+
+import java.util.List;
+
+import org.yaml.snakeyaml.events.Event;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public interface Parser {
+ public boolean checkEvent(List<Class<? extends Event>> choices);
+
+ public boolean checkEvent(Class<? extends Event> choice);
+
+ public Event peekEvent();
+
+ public Event getEvent();
+
+}
diff --git a/src/main/java/org/yaml/snakeyaml/parser/ParserException.java b/src/main/java/org/yaml/snakeyaml/parser/ParserException.java
new file mode 100644
index 00000000..9a866b67
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/parser/ParserException.java
@@ -0,0 +1,18 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.parser;
+
+import org.yaml.snakeyaml.error.Mark;
+import org.yaml.snakeyaml.error.MarkedYAMLException;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public class ParserException extends MarkedYAMLException {
+ private static final long serialVersionUID = -2349253802798398038L;
+
+ public ParserException(String context, Mark contextMark, String problem, Mark problemMark) {
+ super(context, contextMark, problem, problemMark, null);
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/parser/ParserImpl.java b/src/main/java/org/yaml/snakeyaml/parser/ParserImpl.java
new file mode 100644
index 00000000..865a1d03
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/parser/ParserImpl.java
@@ -0,0 +1,855 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.parser;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.yaml.snakeyaml.error.Mark;
+import org.yaml.snakeyaml.error.YAMLException;
+import org.yaml.snakeyaml.events.AliasEvent;
+import org.yaml.snakeyaml.events.DocumentEndEvent;
+import org.yaml.snakeyaml.events.DocumentStartEvent;
+import org.yaml.snakeyaml.events.Event;
+import org.yaml.snakeyaml.events.MappingEndEvent;
+import org.yaml.snakeyaml.events.MappingStartEvent;
+import org.yaml.snakeyaml.events.ScalarEvent;
+import org.yaml.snakeyaml.events.SequenceEndEvent;
+import org.yaml.snakeyaml.events.SequenceStartEvent;
+import org.yaml.snakeyaml.events.StreamEndEvent;
+import org.yaml.snakeyaml.events.StreamStartEvent;
+import org.yaml.snakeyaml.scanner.Scanner;
+import org.yaml.snakeyaml.scanner.ScannerImpl;
+import org.yaml.snakeyaml.tokens.AliasToken;
+import org.yaml.snakeyaml.tokens.AnchorToken;
+import org.yaml.snakeyaml.tokens.BlockEndToken;
+import org.yaml.snakeyaml.tokens.BlockEntryToken;
+import org.yaml.snakeyaml.tokens.BlockMappingStartToken;
+import org.yaml.snakeyaml.tokens.BlockSequenceStartToken;
+import org.yaml.snakeyaml.tokens.DirectiveToken;
+import org.yaml.snakeyaml.tokens.DocumentEndToken;
+import org.yaml.snakeyaml.tokens.DocumentStartToken;
+import org.yaml.snakeyaml.tokens.FlowEntryToken;
+import org.yaml.snakeyaml.tokens.FlowMappingEndToken;
+import org.yaml.snakeyaml.tokens.FlowMappingStartToken;
+import org.yaml.snakeyaml.tokens.FlowSequenceEndToken;
+import org.yaml.snakeyaml.tokens.FlowSequenceStartToken;
+import org.yaml.snakeyaml.tokens.KeyToken;
+import org.yaml.snakeyaml.tokens.ScalarToken;
+import org.yaml.snakeyaml.tokens.StreamEndToken;
+import org.yaml.snakeyaml.tokens.StreamStartToken;
+import org.yaml.snakeyaml.tokens.TagToken;
+import org.yaml.snakeyaml.tokens.Token;
+import org.yaml.snakeyaml.tokens.ValueToken;
+
+/**
+ * <pre>
+ * # The following YAML grammar is LL(1) and is parsed by a recursive descent
+ * parser.
+ * stream ::= STREAM-START implicit_document? explicit_document* STREAM-END
+ * implicit_document ::= block_node DOCUMENT-END*
+ * explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
+ * block_node_or_indentless_sequence ::=
+ * ALIAS
+ * | properties (block_content | indentless_block_sequence)?
+ * | block_content
+ * | indentless_block_sequence
+ * block_node ::= ALIAS
+ * | properties block_content?
+ * | block_content
+ * flow_node ::= ALIAS
+ * | properties flow_content?
+ * | flow_content
+ * properties ::= TAG ANCHOR? | ANCHOR TAG?
+ * block_content ::= block_collection | flow_collection | SCALAR
+ * flow_content ::= flow_collection | SCALAR
+ * block_collection ::= block_sequence | block_mapping
+ * flow_collection ::= flow_sequence | flow_mapping
+ * block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END
+ * indentless_sequence ::= (BLOCK-ENTRY block_node?)+
+ * block_mapping ::= BLOCK-MAPPING_START
+ * ((KEY block_node_or_indentless_sequence?)?
+ * (VALUE block_node_or_indentless_sequence?)?)*
+ * BLOCK-END
+ * flow_sequence ::= FLOW-SEQUENCE-START
+ * (flow_sequence_entry FLOW-ENTRY)*
+ * flow_sequence_entry?
+ * FLOW-SEQUENCE-END
+ * flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
+ * flow_mapping ::= FLOW-MAPPING-START
+ * (flow_mapping_entry FLOW-ENTRY)*
+ * flow_mapping_entry?
+ * FLOW-MAPPING-END
+ * flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
+ * FIRST sets:
+ * stream: { STREAM-START }
+ * explicit_document: { DIRECTIVE DOCUMENT-START }
+ * implicit_document: FIRST(block_node)
+ * block_node: { ALIAS TAG ANCHOR SCALAR BLOCK-SEQUENCE-START BLOCK-MAPPING-START FLOW-SEQUENCE-START FLOW-MAPPING-START }
+ * flow_node: { ALIAS ANCHOR TAG SCALAR FLOW-SEQUENCE-START FLOW-MAPPING-START }
+ * block_content: { BLOCK-SEQUENCE-START BLOCK-MAPPING-START FLOW-SEQUENCE-START FLOW-MAPPING-START SCALAR }
+ * flow_content: { FLOW-SEQUENCE-START FLOW-MAPPING-START SCALAR }
+ * block_collection: { BLOCK-SEQUENCE-START BLOCK-MAPPING-START }
+ * flow_collection: { FLOW-SEQUENCE-START FLOW-MAPPING-START }
+ * block_sequence: { BLOCK-SEQUENCE-START }
+ * block_mapping: { BLOCK-MAPPING-START }
+ * block_node_or_indentless_sequence: { ALIAS ANCHOR TAG SCALAR BLOCK-SEQUENCE-START BLOCK-MAPPING-START FLOW-SEQUENCE-START FLOW-MAPPING-START BLOCK-ENTRY }
+ * indentless_sequence: { ENTRY }
+ * flow_collection: { FLOW-SEQUENCE-START FLOW-MAPPING-START }
+ * flow_sequence: { FLOW-SEQUENCE-START }
+ * flow_mapping: { FLOW-MAPPING-START }
+ * flow_sequence_entry: { ALIAS ANCHOR TAG SCALAR FLOW-SEQUENCE-START FLOW-MAPPING-START KEY }
+ * flow_mapping_entry: { ALIAS ANCHOR TAG SCALAR FLOW-SEQUENCE-START FLOW-MAPPING-START KEY }
+ * </pre>
+ *
+ * Since writing a recursive-descendant parser is a straightforward task, we do
+ * not give many comments here.
+ *
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public final class ParserImpl implements Parser {
+ private static final Map<String, String> DEFAULT_TAGS = new HashMap<String, String>();
+ static {
+ DEFAULT_TAGS.put("!", "!");
+ DEFAULT_TAGS.put("!!", "tag:yaml.org,2002:");
+ }
+
+ private final Scanner scanner;
+ private Event currentEvent;
+ private List<Integer> yamlVersion;
+ private Map<String, String> tagHandles;
+ private final LinkedList<Production> states;
+ private final LinkedList<Mark> marks;
+ private Production state;
+
+ public ParserImpl(org.yaml.snakeyaml.reader.Reader reader) {
+ this.scanner = new ScannerImpl(reader);
+ currentEvent = null;
+ yamlVersion = null;
+ tagHandles = new HashMap<String, String>();
+ states = new LinkedList<Production>();
+ marks = new LinkedList<Mark>();
+ state = new ParseStreamStart();
+ }
+
+ /**
+ * Check the type of the next event.
+ */
+ public boolean checkEvent(List<Class<? extends Event>> choices) {
+ peekEvent();
+ if (currentEvent != null) {
+ if (choices.size() == 0) {
+ return true;
+ }
+ for (Class<? extends Event> class1 : choices) {
+ if (class1.isInstance(currentEvent)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Check the type of the next event.
+ */
+ public boolean checkEvent(Class<? extends Event> cls) {
+ List<Class<? extends Event>> list = new ArrayList<Class<? extends Event>>(1);
+ list.add(cls);
+ return checkEvent(list);
+ }
+
+ /*
+ * Get the next event.
+ */
+ public Event peekEvent() {
+ if (currentEvent == null) {
+ if (state != null) {
+ currentEvent = state.produce();
+ }
+ }
+ return currentEvent;
+ }
+
+ /*
+ * Get the next event and proceed further.
+ */
+ public Event getEvent() {
+ peekEvent();
+ Event value = currentEvent;
+ currentEvent = null;
+ return value;
+ }
+
+ /**
+ * <pre>
+ * stream ::= STREAM-START implicit_document? explicit_document* STREAM-END
+ * implicit_document ::= block_node DOCUMENT-END*
+ * explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
+ * </pre>
+ */
+ private class ParseStreamStart implements Production {
+ public Event produce() {
+ // Parse the stream start.
+ StreamStartToken token = (StreamStartToken) scanner.getToken();
+ Event event = new StreamStartEvent(token.getStartMark(), token.getEndMark());
+ // Prepare the next state.
+ state = new ParseImplicitDocumentStart();
+ return event;
+ }
+ }
+
+ private class ParseImplicitDocumentStart implements Production {
+ public Event produce() {
+ // Parse an implicit document.
+ List<Class<? extends Token>> choices = new ArrayList<Class<? extends Token>>();
+ choices.add(DirectiveToken.class);
+ choices.add(DocumentStartToken.class);
+ choices.add(StreamEndToken.class);
+ if (!scanner.checkToken(choices)) {
+ tagHandles = DEFAULT_TAGS;
+ Token token = scanner.peekToken();
+ Mark startMark = token.getStartMark();
+ Mark endMark = startMark;
+ Event event = new DocumentStartEvent(startMark, endMark, false, null, null);
+ // Prepare the next state.
+ states.add(new ParseDocumentEnd());
+ state = new ParseBlockNode();
+ return event;
+ } else {
+ Production p = new ParseDocumentStart();
+ return p.produce();
+ }
+ }
+ }
+
+ private class ParseDocumentStart implements Production {
+ @SuppressWarnings("unchecked")
+ public Event produce() {
+ // Parse any extra document end indicators.
+ while (scanner.checkToken(DocumentEndToken.class)) {
+ scanner.getToken();
+ }
+ // Parse an explicit document.
+ Event event;
+ if (!scanner.checkToken(StreamEndToken.class)) {
+ Token token = scanner.peekToken();
+ Mark startMark = token.getStartMark();
+ List<Object> version_tags = processDirectives();
+ List<Object> version = (List<Object>) version_tags.get(0);
+ Map<String, String> tags = (Map<String, String>) version_tags.get(1);
+ if (!scanner.checkToken(DocumentStartToken.class)) {
+ throw new ParserException(null, null, "expected '<document start>', but found "
+ + scanner.peekToken().getTokenId(), scanner.peekToken().getStartMark());
+ }
+ token = scanner.getToken();
+ Mark endMark = token.getEndMark();
+ Integer[] versionInteger;
+ if (version != null) {
+ versionInteger = new Integer[2];
+ versionInteger = version.toArray(versionInteger);
+ } else {
+ versionInteger = null;
+ }
+ event = new DocumentStartEvent(startMark, endMark, true, versionInteger, tags);
+ states.add(new ParseDocumentEnd());
+ state = new ParseDocumentContent();
+ } else {
+ // Parse the end of the stream.
+ StreamEndToken token = (StreamEndToken) scanner.getToken();
+ event = new StreamEndEvent(token.getStartMark(), token.getEndMark());
+ if (!states.isEmpty()) {
+ throw new YAMLException("Unexpected end of stream. States left: " + states);
+ }
+ if (!marks.isEmpty()) {
+ throw new YAMLException("Unexpected end of stream. Marks left: " + marks);
+ }
+ state = null;
+ }
+ return event;
+ }
+ }
+
+ private class ParseDocumentEnd implements Production {
+ public Event produce() {
+ // Parse the document end.
+ Token token = scanner.peekToken();
+ Mark startMark = token.getStartMark();
+ Mark endMark = startMark;
+ boolean explicit = false;
+ if (scanner.checkToken(DocumentEndToken.class)) {
+ token = scanner.getToken();
+ endMark = token.getEndMark();
+ explicit = true;
+ }
+ Event event = new DocumentEndEvent(startMark, endMark, explicit);
+ // Prepare the next state.
+ state = new ParseDocumentStart();
+ return event;
+ }
+ }
+
+ private class ParseDocumentContent implements Production {
+ public Event produce() {
+ List<Class<? extends Token>> choices = new ArrayList<Class<? extends Token>>();
+ choices.add(DirectiveToken.class);
+ choices.add(DocumentStartToken.class);
+ choices.add(DocumentEndToken.class);
+ choices.add(StreamEndToken.class);
+ Event event;
+ if (scanner.checkToken(choices)) {
+ event = processEmptyScalar(scanner.peekToken().getStartMark());
+ state = states.removeLast();
+ return event;
+ } else {
+ Production p = new ParseBlockNode();
+ return p.produce();
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private List<Object> processDirectives() {
+ yamlVersion = null;
+ tagHandles = new HashMap<String, String>();
+ while (scanner.checkToken(DirectiveToken.class)) {
+ DirectiveToken token = (DirectiveToken) scanner.getToken();
+ if (token.getName().equals("YAML")) {
+ if (yamlVersion != null) {
+ throw new ParserException(null, null, "found duplicate YAML directive", token
+ .getStartMark());
+ }
+ List<Integer> value = (List<Integer>) token.getValue();
+ Integer major = value.get(0);
+ if (major != 1) {
+ throw new ParserException(null, null,
+ "found incompatible YAML document (version 1.* is required)", token
+ .getStartMark());
+ }
+ yamlVersion = (List<Integer>) token.getValue();
+ } else if (token.getName().equals("TAG")) {
+ List<String> value = (List<String>) token.getValue();
+ String handle = value.get(0);
+ String prefix = value.get(1);
+ if (tagHandles.containsKey(handle)) {
+ throw new ParserException(null, null, "duplicate tag handle " + handle, token
+ .getStartMark());
+ }
+ tagHandles.put(handle, prefix);
+ }
+ }
+ List<Object> value = new ArrayList<Object>(2);
+ value.add(yamlVersion);
+ if (!tagHandles.isEmpty()) {
+ value.add(new HashMap<String, String>(tagHandles));
+ } else {
+ value.add(new HashMap<String, String>());
+ }
+ for (String key : DEFAULT_TAGS.keySet()) {
+ if (!tagHandles.containsKey(key)) {
+ tagHandles.put(key, DEFAULT_TAGS.get(key));
+ }
+ }
+ return value;
+ }
+
+ /**
+ * <pre>
+ * block_node_or_indentless_sequence ::= ALIAS
+ * | properties (block_content | indentless_block_sequence)?
+ * | block_content
+ * | indentless_block_sequence
+ * block_node ::= ALIAS
+ * | properties block_content?
+ * | block_content
+ * flow_node ::= ALIAS
+ * | properties flow_content?
+ * | flow_content
+ * properties ::= TAG ANCHOR? | ANCHOR TAG?
+ * block_content ::= block_collection | flow_collection | SCALAR
+ * flow_content ::= flow_collection | SCALAR
+ * block_collection ::= block_sequence | block_mapping
+ * flow_collection ::= flow_sequence | flow_mapping
+ * </pre>
+ */
+
+ private class ParseBlockNode implements Production {
+ public Event produce() {
+ return parseNode(true, false);
+ }
+ }
+
+ private Event parseFlowNode() {
+ return parseNode(false, false);
+ }
+
+ private Event parseBlockNodeOrIndentlessSequence() {
+ return parseNode(true, true);
+ }
+
+ private Event parseNode(boolean block, boolean indentlessSequence) {
+ Event event;
+ Mark startMark = null;
+ Mark endMark = null;
+ Mark tagMark = null;
+ if (scanner.checkToken(AliasToken.class)) {
+ AliasToken token = (AliasToken) scanner.getToken();
+ event = new AliasEvent(token.getValue(), token.getStartMark(), token.getEndMark());
+ state = states.removeLast();
+ } else {
+ String anchor = null;
+ String[] tagTokenTag = null;
+ if (scanner.checkToken(AnchorToken.class)) {
+ AnchorToken token = (AnchorToken) scanner.getToken();
+ startMark = token.getStartMark();
+ endMark = token.getEndMark();
+ anchor = token.getValue();
+ if (scanner.checkToken(TagToken.class)) {
+ TagToken tagToken = (TagToken) scanner.getToken();
+ tagMark = tagToken.getStartMark();
+ endMark = tagToken.getEndMark();
+ tagTokenTag = tagToken.getValue();
+ }
+ } else if (scanner.checkToken(TagToken.class)) {
+ TagToken tagToken = (TagToken) scanner.getToken();
+ startMark = tagToken.getStartMark();
+ tagMark = startMark;
+ endMark = tagToken.getEndMark();
+ tagTokenTag = tagToken.getValue();
+ if (scanner.checkToken(AnchorToken.class)) {
+ AnchorToken token = (AnchorToken) scanner.getToken();
+ endMark = token.getEndMark();
+ anchor = token.getValue();
+ }
+ }
+ String tag = null;
+ if (tagTokenTag != null) {
+ String handle = tagTokenTag[0];
+ String suffix = tagTokenTag[1];
+ if (handle != null) {
+ if (!tagHandles.containsKey(handle)) {
+ throw new ParserException("while parsing a node", startMark,
+ "found undefined tag handle " + handle, tagMark);
+ }
+ tag = tagHandles.get(handle) + suffix;
+ } else {
+ tag = suffix;
+ }
+ }
+ if (startMark == null) {
+ startMark = scanner.peekToken().getStartMark();
+ endMark = startMark;
+ }
+ event = null;
+ boolean implicit = (tag == null || tag.equals("!"));
+ if (indentlessSequence && scanner.checkToken(BlockEntryToken.class)) {
+ endMark = scanner.peekToken().getEndMark();
+ event = new SequenceStartEvent(anchor, tag, implicit, startMark, endMark,
+ Boolean.FALSE);
+ state = new ParseIndentlessSequenceEntry();
+ } else {
+ if (scanner.checkToken(ScalarToken.class)) {
+ ScalarToken token = (ScalarToken) scanner.getToken();
+ endMark = token.getEndMark();
+ boolean[] implicitValues = new boolean[2];
+ if ((token.getPlain() && tag == null) || "!".equals(tag)) {
+ implicitValues[0] = true;
+ implicitValues[1] = false;
+ } else if (tag == null) {
+ implicitValues[0] = false;
+ implicitValues[1] = true;
+ } else {
+ implicitValues[0] = false;
+ implicitValues[1] = false;
+ }
+ event = new ScalarEvent(anchor, tag, implicitValues, token.getValue(),
+ startMark, endMark, token.getStyle());
+ state = states.removeLast();
+ } else if (scanner.checkToken(FlowSequenceStartToken.class)) {
+ endMark = scanner.peekToken().getEndMark();
+ event = new SequenceStartEvent(anchor, tag, implicit, startMark, endMark,
+ Boolean.TRUE);
+ state = new ParseFlowSequenceFirstEntry();
+ } else if (scanner.checkToken(FlowMappingStartToken.class)) {
+ endMark = scanner.peekToken().getEndMark();
+ event = new MappingStartEvent(anchor, tag, implicit, startMark, endMark,
+ Boolean.TRUE);
+ state = new ParseFlowMappingFirstKey();
+ } else if (block && scanner.checkToken(BlockSequenceStartToken.class)) {
+ endMark = scanner.peekToken().getStartMark();
+ event = new SequenceStartEvent(anchor, tag, implicit, startMark, endMark,
+ Boolean.FALSE);
+ state = new ParseBlockSequenceFirstEntry();
+ } else if (block && scanner.checkToken(BlockMappingStartToken.class)) {
+ endMark = scanner.peekToken().getStartMark();
+ event = new MappingStartEvent(anchor, tag, implicit, startMark, endMark,
+ Boolean.FALSE);
+ state = new ParseBlockMappingFirstKey();
+ } else if (anchor != null || tag != null) {
+ // Empty scalars are allowed even if a tag or an anchor is
+ // specified.
+ boolean[] implicitValues = new boolean[2];
+ implicitValues[0] = implicit;
+ implicitValues[1] = false;
+ event = new ScalarEvent(anchor, tag, implicitValues, "", startMark, endMark,
+ (char) 0);
+ state = states.removeLast();
+ } else {
+ String node;
+ if (block) {
+ node = "block";
+ } else {
+ node = "flow";
+ }
+ Token token = scanner.peekToken();
+ throw new ParserException("while parsing a " + node + " node", startMark,
+ "expected the node content, but found " + token.getTokenId(), token
+ .getStartMark());
+ }
+ }
+ }
+ return event;
+ }
+
+ // block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)*
+ // BLOCK-END
+
+ private class ParseBlockSequenceFirstEntry implements Production {
+ public Event produce() {
+ Token token = scanner.getToken();
+ marks.add(token.getStartMark());
+ return new ParseBlockSequenceEntry().produce();
+ }
+ }
+
+ private class ParseBlockSequenceEntry implements Production {
+ public Event produce() {
+ if (scanner.checkToken(BlockEntryToken.class)) {
+ BlockEntryToken token = (BlockEntryToken) scanner.getToken();
+ List<Class<? extends Token>> choices = new ArrayList<Class<? extends Token>>();
+ choices.add(BlockEntryToken.class);
+ choices.add(BlockEndToken.class);
+ if (!scanner.checkToken(choices)) {
+ states.add(new ParseBlockSequenceEntry());
+ return new ParseBlockNode().produce();
+ } else {
+ state = new ParseBlockSequenceEntry();
+ return processEmptyScalar(token.getEndMark());
+ }
+ }
+ if (!scanner.checkToken(BlockEndToken.class)) {
+ Token token = scanner.peekToken();
+ throw new ParserException("while parsing a block collection", marks.getLast(),
+ "expected <block end>, but found " + token.getTokenId(), token
+ .getStartMark());
+ }
+ Token token = scanner.getToken();
+ Event event = new SequenceEndEvent(token.getStartMark(), token.getEndMark());
+ state = states.removeLast();
+ marks.removeLast();
+ return event;
+ }
+ }
+
+ // indentless_sequence ::= (BLOCK-ENTRY block_node?)+
+
+ private class ParseIndentlessSequenceEntry implements Production {
+ public Event produce() {
+ if (scanner.checkToken(BlockEntryToken.class)) {
+ Token token = scanner.getToken();
+ List<Class<? extends Token>> choices = new ArrayList<Class<? extends Token>>();
+ choices.add(BlockEntryToken.class);
+ choices.add(KeyToken.class);
+ choices.add(ValueToken.class);
+ choices.add(BlockEndToken.class);
+ if (!scanner.checkToken(choices)) {
+ states.add(new ParseIndentlessSequenceEntry());
+ return new ParseBlockNode().produce();
+ } else {
+ state = new ParseIndentlessSequenceEntry();
+ return processEmptyScalar(token.getEndMark());
+ }
+ }
+ Token token = scanner.peekToken();
+ Event event = new SequenceEndEvent(token.getStartMark(), token.getEndMark());
+ state = states.removeLast();
+ return event;
+ }
+ }
+
+ private class ParseBlockMappingFirstKey implements Production {
+ public Event produce() {
+ Token token = scanner.getToken();
+ marks.add(token.getStartMark());
+ return new ParseBlockMappingKey().produce();
+ }
+ }
+
+ private class ParseBlockMappingKey implements Production {
+ public Event produce() {
+ if (scanner.checkToken(KeyToken.class)) {
+ Token token = scanner.getToken();
+ List<Class<? extends Token>> choices = new ArrayList<Class<? extends Token>>();
+ choices.add(KeyToken.class);
+ choices.add(ValueToken.class);
+ choices.add(BlockEndToken.class);
+ if (!scanner.checkToken(choices)) {
+ states.add(new ParseBlockMappingValue());
+ return parseBlockNodeOrIndentlessSequence();
+ } else {
+ state = new ParseBlockMappingValue();
+ return processEmptyScalar(token.getEndMark());
+ }
+ }
+ if (!scanner.checkToken(BlockEndToken.class)) {
+ Token token = scanner.peekToken();
+ throw new ParserException("while parsing a block mapping", marks.getLast(),
+ "expected <block end>, but found " + token.getTokenId(), token
+ .getStartMark());
+ }
+ Token token = scanner.getToken();
+ Event event = new MappingEndEvent(token.getStartMark(), token.getEndMark());
+ state = states.removeLast();
+ marks.removeLast();
+ return event;
+ }
+ }
+
+ private class ParseBlockMappingValue implements Production {
+ public Event produce() {
+ if (scanner.checkToken(ValueToken.class)) {
+ Token token = scanner.getToken();
+ List<Class<? extends Token>> choices = new ArrayList<Class<? extends Token>>();
+ choices.add(KeyToken.class);
+ choices.add(ValueToken.class);
+ choices.add(BlockEndToken.class);
+ if (!scanner.checkToken(choices)) {
+ states.add(new ParseBlockMappingKey());
+ return parseBlockNodeOrIndentlessSequence();
+ } else {
+ state = new ParseBlockMappingKey();
+ return processEmptyScalar(token.getEndMark());
+ }
+ }
+ state = new ParseBlockMappingKey();
+ Token token = scanner.peekToken();
+ return processEmptyScalar(token.getStartMark());
+ }
+ }
+
+ /**
+ * <pre>
+ * flow_sequence ::= FLOW-SEQUENCE-START
+ * (flow_sequence_entry FLOW-ENTRY)*
+ * flow_sequence_entry?
+ * FLOW-SEQUENCE-END
+ * flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
+ * Note that while production rules for both flow_sequence_entry and
+ * flow_mapping_entry are equal, their interpretations are different.
+ * For `flow_sequence_entry`, the part `KEY flow_node? (VALUE flow_node?)?`
+ * generate an inline mapping (set syntax).
+ * </pre>
+ */
+ private class ParseFlowSequenceFirstEntry implements Production {
+ public Event produce() {
+ Token token = scanner.getToken();
+ marks.add(token.getStartMark());
+ return new ParseFlowSequenceEntry(true).produce();
+ }
+ }
+
+ private class ParseFlowSequenceEntry implements Production {
+ private boolean first = false;
+
+ public ParseFlowSequenceEntry(boolean first) {
+ this.first = first;
+ }
+
+ public Event produce() {
+ if (!scanner.checkToken(FlowSequenceEndToken.class)) {
+ if (!first) {
+ if (scanner.checkToken(FlowEntryToken.class)) {
+ scanner.getToken();
+ } else {
+ Token token = scanner.peekToken();
+ throw new ParserException("while parsing a flow sequence", marks.getLast(),
+ "expected ',' or ']', but got " + token.getTokenId(), token
+ .getStartMark());
+ }
+ }
+ if (scanner.checkToken(KeyToken.class)) {
+ Token token = scanner.peekToken();
+ Event event = new MappingStartEvent(null, null, true, token.getStartMark(),
+ token.getEndMark(), Boolean.TRUE);
+ state = new ParseFlowSequenceEntryMappingKey();
+ return event;
+ } else if (!scanner.checkToken(FlowSequenceEndToken.class)) {
+ states.add(new ParseFlowSequenceEntry(false));
+ return parseFlowNode();
+ }
+ }
+ Token token = scanner.getToken();
+ Event event = new SequenceEndEvent(token.getStartMark(), token.getEndMark());
+ state = states.removeLast();
+ marks.removeLast();
+ return event;
+ }
+ }
+
+ private class ParseFlowSequenceEntryMappingKey implements Production {
+ public Event produce() {
+ Token token = scanner.getToken();
+ List<Class<? extends Token>> choices = new ArrayList<Class<? extends Token>>();
+ choices.add(ValueToken.class);
+ choices.add(FlowEntryToken.class);
+ choices.add(FlowSequenceEndToken.class);
+ if (!scanner.checkToken(choices)) {
+ states.add(new ParseFlowSequenceEntryMappingValue());
+ return parseFlowNode();
+ } else {
+ state = new ParseFlowSequenceEntryMappingValue();
+ return processEmptyScalar(token.getEndMark());
+ }
+ }
+ }
+
+ private class ParseFlowSequenceEntryMappingValue implements Production {
+ public Event produce() {
+ if (scanner.checkToken(ValueToken.class)) {
+ Token token = scanner.getToken();
+ List<Class<? extends Token>> choices = new ArrayList<Class<? extends Token>>();
+ choices.add(FlowEntryToken.class);
+ choices.add(FlowSequenceEndToken.class);
+ if (!scanner.checkToken(choices)) {
+ states.add(new ParseFlowSequenceEntryMappingEnd());
+ return parseFlowNode();
+ } else {
+ state = new ParseFlowSequenceEntryMappingEnd();
+ return processEmptyScalar(token.getEndMark());
+ }
+ } else {
+ state = new ParseFlowSequenceEntryMappingEnd();
+ Token token = scanner.peekToken();
+ return processEmptyScalar(token.getStartMark());
+ }
+ }
+ }
+
+ private class ParseFlowSequenceEntryMappingEnd implements Production {
+ public Event produce() {
+ state = new ParseFlowSequenceEntry(false);
+ Token token = scanner.peekToken();
+ return new MappingEndEvent(token.getStartMark(), token.getEndMark());
+ }
+ }
+
+ /**
+ * <pre>
+ * flow_mapping ::= FLOW-MAPPING-START
+ * (flow_mapping_entry FLOW-ENTRY)*
+ * flow_mapping_entry?
+ * FLOW-MAPPING-END
+ * flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
+ * </pre>
+ */
+ private class ParseFlowMappingFirstKey implements Production {
+ public Event produce() {
+ Token token = scanner.getToken();
+ marks.add(token.getStartMark());
+ return new ParseFlowMappingKey(true).produce();
+ }
+ }
+
+ private class ParseFlowMappingKey implements Production {
+ private boolean first = false;
+
+ public ParseFlowMappingKey(boolean first) {
+ this.first = first;
+ }
+
+ public Event produce() {
+ if (!scanner.checkToken(FlowMappingEndToken.class)) {
+ if (!first) {
+ if (scanner.checkToken(FlowEntryToken.class)) {
+ scanner.getToken();
+ } else {
+ Token token = scanner.peekToken();
+ throw new ParserException("while parsing a flow mapping", marks.getLast(),
+ "expected ',' or '}', but got " + token.getTokenId(), token
+ .getStartMark());
+ }
+ }
+ if (scanner.checkToken(KeyToken.class)) {
+ Token token = scanner.getToken();
+ List<Class<? extends Token>> choices = new ArrayList<Class<? extends Token>>();
+ choices.add(ValueToken.class);
+ choices.add(FlowEntryToken.class);
+ choices.add(FlowMappingEndToken.class);
+ if (!scanner.checkToken(choices)) {
+ states.add(new ParseFlowMappingValue());
+ return parseFlowNode();
+ } else {
+ state = new ParseFlowMappingValue();
+ return processEmptyScalar(token.getEndMark());
+ }
+ } else if (!scanner.checkToken(FlowMappingEndToken.class)) {
+ states.add(new ParseFlowMappingEmptyValue());
+ return parseFlowNode();
+ }
+ }
+ Token token = scanner.getToken();
+ Event event = new MappingEndEvent(token.getStartMark(), token.getEndMark());
+ state = states.removeLast();
+ marks.removeLast();
+ return event;
+ }
+ }
+
+ private class ParseFlowMappingValue implements Production {
+ public Event produce() {
+ if (scanner.checkToken(ValueToken.class)) {
+ Token token = scanner.getToken();
+ List<Class<? extends Token>> choices = new ArrayList<Class<? extends Token>>();
+ choices.add(FlowEntryToken.class);
+ choices.add(FlowMappingEndToken.class);
+ if (!scanner.checkToken(choices)) {
+ states.add(new ParseFlowMappingKey(false));
+ return parseFlowNode();
+ } else {
+ state = new ParseFlowMappingKey(false);
+ return processEmptyScalar(token.getEndMark());
+ }
+ } else {
+ state = new ParseFlowMappingKey(false);
+ Token token = scanner.peekToken();
+ return processEmptyScalar(token.getStartMark());
+ }
+ }
+ }
+
+ private class ParseFlowMappingEmptyValue implements Production {
+ public Event produce() {
+ state = new ParseFlowMappingKey(false);
+ return processEmptyScalar(scanner.peekToken().getStartMark());
+ }
+ }
+
+ /**
+ * <pre>
+ * block_mapping ::= BLOCK-MAPPING_START
+ * ((KEY block_node_or_indentless_sequence?)?
+ * (VALUE block_node_or_indentless_sequence?)?)*
+ * BLOCK-END
+ * </pre>
+ */
+ private Event processEmptyScalar(Mark mark) {
+ boolean[] value = new boolean[2];
+ value[0] = true;
+ value[1] = false;
+ return new ScalarEvent(null, null, value, "", mark, mark, (char) 0);
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/parser/Production.java b/src/main/java/org/yaml/snakeyaml/parser/Production.java
new file mode 100644
index 00000000..92e6bc4a
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/parser/Production.java
@@ -0,0 +1,10 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.parser;
+
+import org.yaml.snakeyaml.events.Event;
+
+interface Production {
+ public Event produce();
+}
diff --git a/src/main/java/org/yaml/snakeyaml/reader/Reader.java b/src/main/java/org/yaml/snakeyaml/reader/Reader.java
new file mode 100644
index 00000000..885bb74a
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/reader/Reader.java
@@ -0,0 +1,175 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.reader;
+
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.yaml.snakeyaml.error.Mark;
+import org.yaml.snakeyaml.error.YAMLException;
+
+/**
+ * Reader: determines the data encoding and converts it to unicode, checks if
+ * characters are in allowed range, adds '\0' to the end.
+ *
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public class Reader {
+ // NON_PRINTABLE changed from PyYAML: \uFFFD excluded because Java returns
+ // it in case of data corruption
+ final static Pattern NON_PRINTABLE = Pattern
+ .compile("[^\t\n\r\u0020-\u007E\u0085\u00A0-\uD7FF\uE000-\uFFFC]");
+ private final static String LINEBR = "\n\u0085\u2028\u2029";
+
+ private String name;
+ private final java.io.Reader stream;
+ private int pointer = 0;
+ private boolean eof = true;
+ private final StringBuffer buffer;
+ private int index = 0;
+ private int line = 0;
+ private int column = 0;
+
+ public Reader(String stream) {
+ this.name = "<string>";
+ this.buffer = new StringBuffer();
+ checkPrintable(stream);
+ this.buffer.append(stream);
+ this.stream = null;
+ this.eof = true;
+ }
+
+ public Reader(java.io.Reader reader) {
+ this.name = "<reader>";
+ this.buffer = new StringBuffer();
+ this.stream = reader;
+ this.eof = false;
+ }
+
+ void checkPrintable(CharSequence data) {
+ Matcher em = NON_PRINTABLE.matcher(data);
+ if (em.find()) {
+ int position = this.index + this.buffer.length() - this.pointer + em.start();
+ throw new ReaderException(name, position, em.group().charAt(0),
+ " special characters are not allowed");
+ }
+ }
+
+ public Mark getMark() {
+ if (this.stream == null) {
+ return new Mark(name, this.index, this.line, this.column, this.buffer.toString(),
+ this.pointer);
+ } else {
+ return new Mark(name, this.index, this.line, this.column, null, 0);
+ }
+ }
+
+ public void forward() {
+ forward(1);
+ }
+
+ /**
+ * read the next length characters and move the pointer.
+ *
+ * @param length
+ */
+ public void forward(int length) {
+ if (this.pointer + length + 1 >= this.buffer.length()) {
+ update(length + 1);
+ }
+ char ch = 0;
+ for (int i = 0; i < length; i++) {
+ ch = this.buffer.charAt(this.pointer);
+ this.pointer++;
+ this.index++;
+ if (LINEBR.indexOf(ch) != -1
+ || (ch == '\r' && this.buffer.charAt(this.pointer) != '\n')) {
+ this.line++;
+ this.column = 0;
+ } else if (ch != '\uFEFF') {
+ this.column++;
+ }
+ }
+ }
+
+ public char peek() {
+ return peek(0);
+ }
+
+ /**
+ * Peek the next index-th character
+ *
+ * @param index
+ * @return
+ */
+ public char peek(int index) {
+ if (this.pointer + index + 1 > this.buffer.length()) {
+ update(index + 1);
+ }
+ return this.buffer.charAt(this.pointer + index);
+ }
+
+ /**
+ * peek the next length characters
+ *
+ * @param length
+ * @return
+ */
+ public String prefix(int length) {
+ if (this.pointer + length >= this.buffer.length()) {
+ update(length);
+ }
+ if (this.pointer + length > this.buffer.length()) {
+ return this.buffer.substring(this.pointer, this.buffer.length());
+ } else {
+ return this.buffer.substring(this.pointer, this.pointer + length);
+ }
+ }
+
+ private void update(int length) {
+ this.buffer.delete(0, this.pointer);
+ this.pointer = 0;
+ while (this.buffer.length() < length) {
+ String rawData = "";
+ if (!this.eof) {
+ char[] data = new char[1024];
+ int converted = -2;
+ try {
+ converted = this.stream.read(data);
+ } catch (IOException ioe) {
+ throw new YAMLException(ioe);
+ }
+ if (converted == -1) {
+ this.eof = true;
+ } else {
+ rawData = new String(data, 0, converted);
+ }
+ }
+ checkPrintable(rawData);
+ this.buffer.append(rawData);
+ if (this.eof) {
+ this.buffer.append('\0');
+ break;
+ }
+ }
+ }
+
+ public int getColumn() {
+ return column;
+ }
+
+ public Charset getEncoding() {
+ return Charset.forName(((UnicodeReader) this.stream).getEncoding());
+ }
+
+ public int getIndex() {
+ return index;
+ }
+
+ public int getLine() {
+ return line;
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/reader/ReaderException.java b/src/main/java/org/yaml/snakeyaml/reader/ReaderException.java
new file mode 100644
index 00000000..7239f3f5
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/reader/ReaderException.java
@@ -0,0 +1,26 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.reader;
+
+import org.yaml.snakeyaml.error.YAMLException;
+
+public class ReaderException extends YAMLException {
+ private static final long serialVersionUID = 8710781187529689083L;
+ private String name;
+ private char character;
+ private int position;
+
+ public ReaderException(String name, int position, char character, String message) {
+ super(message);
+ this.name = name;
+ this.character = character;
+ this.position = position;
+ }
+
+ @Override
+ public String toString() {
+ return "unacceptable character #" + Integer.toHexString((int) character).toUpperCase()
+ + " " + getMessage() + "\nin \"" + name + "\", position " + position;
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/reader/UnicodeReader.java b/src/main/java/org/yaml/snakeyaml/reader/UnicodeReader.java
new file mode 100644
index 00000000..07081393
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/reader/UnicodeReader.java
@@ -0,0 +1,105 @@
+package org.yaml.snakeyaml.reader;
+
+/**
+ version: 1.1 / 2007-01-25
+ - changed BOM recognition ordering (longer boms first)
+
+ Original pseudocode : Thomas Weidenfeller
+ Implementation tweaked: Aki Nieminen
+ Implementation changed: Andrey Somov
+ * UTF-32 removed because it is not supported by YAML
+ * no default encoding
+
+ http://www.unicode.org/unicode/faq/utf_bom.html
+ BOMs:
+ 00 00 FE FF = UTF-32, big-endian
+ FF FE 00 00 = UTF-32, little-endian
+ EF BB BF = UTF-8,
+ FE FF = UTF-16, big-endian
+ FF FE = UTF-16, little-endian
+
+ Win2k Notepad:
+ Unicode format = UTF-16LE
+ ***/
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PushbackInputStream;
+
+/**
+ * Generic unicode textreader, which will use BOM mark to identify the encoding
+ * to be used. If BOM is not found then use a given default or system encoding.
+ */
+public class UnicodeReader extends java.io.Reader {
+ PushbackInputStream internalIn;
+ InputStreamReader internalIn2 = null;
+
+ private static final int BOM_SIZE = 3;
+
+ /**
+ *
+ * @param in
+ * InputStream to be read
+ * @param defaultEnc
+ * default encoding if stream does not have BOM marker. Give NULL
+ * to use system-level default.
+ */
+ public UnicodeReader(InputStream in) {
+ internalIn = new PushbackInputStream(in, BOM_SIZE);
+ }
+
+ /**
+ * Get stream encoding or NULL if stream is uninitialized. Call init() or
+ * read() method to initialize it.
+ */
+ public String getEncoding() {
+ return internalIn2.getEncoding();
+ }
+
+ /**
+ * Read-ahead four bytes and check for BOM marks. Extra bytes are unread
+ * back to the stream, only BOM bytes are skipped.
+ */
+ protected void init() throws IOException {
+ if (internalIn2 != null)
+ return;
+
+ String encoding;
+ byte bom[] = new byte[BOM_SIZE];
+ int n, unread;
+ n = internalIn.read(bom, 0, bom.length);
+
+ if ((bom[0] == (byte) 0xEF) && (bom[1] == (byte) 0xBB) && (bom[2] == (byte) 0xBF)) {
+ encoding = "UTF-8";
+ unread = n - 3;
+ } else if ((bom[0] == (byte) 0xFE) && (bom[1] == (byte) 0xFF)) {
+ encoding = "UTF-16BE";
+ unread = n - 2;
+ } else if ((bom[0] == (byte) 0xFF) && (bom[1] == (byte) 0xFE)) {
+ encoding = "UTF-16LE";
+ unread = n - 2;
+ } else {
+ // Unicode BOM mark not found, unread all bytes
+ encoding = "UTF-8";
+ unread = n;
+ }
+
+ if (unread > 0)
+ internalIn.unread(bom, (n - unread), unread);
+
+ // Use given encoding
+ internalIn2 = new InputStreamReader(internalIn, encoding);
+ }
+
+ public void close() throws IOException {
+ init();
+ internalIn2.close();
+ }
+
+ public int read(char[] cbuf, int off, int len) throws IOException {
+ init();
+ return internalIn2.read(cbuf, off, len);
+ }
+
+} \ No newline at end of file
diff --git a/src/main/java/org/yaml/snakeyaml/representer/BaseRepresenter.java b/src/main/java/org/yaml/snakeyaml/representer/BaseRepresenter.java
new file mode 100644
index 00000000..b1c94292
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/representer/BaseRepresenter.java
@@ -0,0 +1,161 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.representer;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.yaml.snakeyaml.error.YAMLException;
+import org.yaml.snakeyaml.nodes.MappingNode;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.ScalarNode;
+import org.yaml.snakeyaml.nodes.SequenceNode;
+import org.yaml.snakeyaml.serializer.Serializer;
+
+public abstract class BaseRepresenter {
+ @SuppressWarnings("unchecked")
+ protected final Map<Class, Represent> representers = new HashMap<Class, Represent>();
+ /**
+ * in Java 'null' is not a type. So we have to keep the null representer
+ * separately otherwise it will coincide with the default representer which
+ * is stored with the key null.
+ */
+ protected Represent nullRepresenter;
+ @SuppressWarnings("unchecked")
+ protected final Map<Class, Represent> multiRepresenters = new HashMap<Class, Represent>();
+ private Character defaultStyle;
+ protected Boolean defaultFlowStyle;
+ protected final Map<Integer, Node> representedObjects = new HashMap<Integer, Node>();
+ private final Set<Object> objectKeeper = new HashSet<Object>();
+ protected Integer aliasKey;// internal memory address
+ protected String rootTag = null;
+
+ public BaseRepresenter(Character default_style, Boolean default_flow_style) {
+ this.defaultStyle = default_style;
+ this.defaultFlowStyle = default_flow_style;
+ }
+
+ public void represent(Serializer serializer, Object data) throws IOException {
+ Node node = representData(data);
+ serializer.serialize(node);
+ representedObjects.clear();
+ objectKeeper.clear();
+ }
+
+ @SuppressWarnings("unchecked")
+ protected Node representData(Object data) {
+ aliasKey = System.identityHashCode(data);// take memory address
+ if (!ignoreAliases(data)) {
+ // check for identity
+ if (representedObjects.containsKey(aliasKey)) {
+ Node node = representedObjects.get(aliasKey);
+ return node;
+ }
+ }
+ // check for null first
+ if (data == null) {
+ Node node = nullRepresenter.representData(data);
+ return node;
+ }
+ // check the same class
+ Node node;
+ Class clazz = data.getClass();
+ if (representers.containsKey(clazz)) {
+ Represent representer = representers.get(clazz);
+ node = representer.representData(data);
+ } else {
+ // check the parents
+ for (Class repr : multiRepresenters.keySet()) {
+ if (repr.isInstance(data)) {
+ Represent representer = multiRepresenters.get(repr);
+ node = representer.representData(data);
+ return node;
+ }
+ }
+ // check array of primitives
+ if (clazz.isArray()) {
+ throw new YAMLException("Arrays of primitives are not fully supported.");
+ }
+ // check defaults
+ if (multiRepresenters.containsKey(null)) {
+ Represent representer = multiRepresenters.get(null);
+ node = representer.representData(data);
+ } else {
+ Represent representer = representers.get(null);
+ node = representer.representData(data);
+ }
+ }
+ return node;
+ }
+
+ protected Node representScalar(String tag, String value, Character style) {
+ if (style == null) {
+ style = this.defaultStyle;
+ }
+ Node node = new ScalarNode(tag, value, null, null, style);
+ representedObjects.put(aliasKey, node);
+ return node;
+ }
+
+ protected Node representScalar(String tag, String value) {
+ return representScalar(tag, value, null);
+ }
+
+ protected Node representSequence(String tag, List<? extends Object> sequence, Boolean flowStyle) {
+ List<Node> value = new LinkedList<Node>();
+ SequenceNode node = new SequenceNode(tag, value, flowStyle);
+ representedObjects.put(aliasKey, node);
+ boolean bestStyle = true;
+ for (Object item : sequence) {
+ Node nodeItem = representData(item);
+ if (!((nodeItem instanceof ScalarNode && ((ScalarNode) nodeItem).getStyle() == null))) {
+ bestStyle = false;
+ }
+ value.add(nodeItem);
+ }
+ if (flowStyle == null) {
+ if (defaultFlowStyle != null) {
+ node.setFlowStyle(defaultFlowStyle);
+ } else {
+ node.setFlowStyle(bestStyle);
+ }
+ }
+ return node;
+ }
+
+ protected Node representMapping(String tag, Map<? extends Object, Object> mapping,
+ Boolean flowStyle) {
+ List<Node[]> value = new LinkedList<Node[]>();
+ MappingNode node = new MappingNode(tag, value, flowStyle);
+ representedObjects.put(aliasKey, node);
+ boolean bestStyle = true;
+ for (Object itemKey : mapping.keySet()) {
+ Object itemValue = mapping.get(itemKey);
+ Node nodeKey = representData(itemKey);
+ Node nodeValue = representData(itemValue);
+ if (!((nodeKey instanceof ScalarNode && ((ScalarNode) nodeKey).getStyle() == null))) {
+ bestStyle = false;
+ }
+ if (!((nodeValue instanceof ScalarNode && ((ScalarNode) nodeValue).getStyle() == null))) {
+ bestStyle = false;
+ }
+ value.add(new Node[] { nodeKey, nodeValue });
+ }
+ if (flowStyle == null) {
+ if (defaultFlowStyle != null) {
+ node.setFlowStyle(defaultFlowStyle);
+ } else {
+ node.setFlowStyle(bestStyle);
+ }
+ }
+ return node;
+ }
+
+ protected abstract boolean ignoreAliases(Object data);
+}
diff --git a/src/main/java/org/yaml/snakeyaml/representer/Represent.java b/src/main/java/org/yaml/snakeyaml/representer/Represent.java
new file mode 100644
index 00000000..e51e7bea
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/representer/Represent.java
@@ -0,0 +1,10 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.representer;
+
+import org.yaml.snakeyaml.nodes.Node;
+
+public interface Represent {
+ public Node representData(Object data);
+}
diff --git a/src/main/java/org/yaml/snakeyaml/representer/Representer.java b/src/main/java/org/yaml/snakeyaml/representer/Representer.java
new file mode 100644
index 00000000..baa4e3e5
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/representer/Representer.java
@@ -0,0 +1,143 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.representer;
+
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.yaml.snakeyaml.TypeDescription;
+import org.yaml.snakeyaml.error.YAMLException;
+import org.yaml.snakeyaml.introspector.FieldProperty;
+import org.yaml.snakeyaml.introspector.MethodProperty;
+import org.yaml.snakeyaml.introspector.Property;
+import org.yaml.snakeyaml.nodes.MappingNode;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.ScalarNode;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public class Representer extends SafeRepresenter {
+ private Map<Class<? extends Object>, String> classTags;
+ private Map<Class<? extends Object>, TypeDescription> classDefinitions;
+
+ public Representer(Character default_style, Boolean default_flow_style) {
+ super(default_style, default_flow_style);
+ classTags = new HashMap<Class<? extends Object>, String>();
+ classDefinitions = new HashMap<Class<? extends Object>, TypeDescription>();
+ this.representers.put(null, new RepresentJavaBean());
+ }
+
+ public Representer() {
+ this(null, null);
+ }
+
+ /**
+ * Make YAML aware how to represent a custom Class. If there is no root
+ * Class assigned in constructor then the 'root' property of this definition
+ * is respected.
+ *
+ * @param definition
+ * to be added to the Constructor
+ * @return the previous value associated with <tt>definition</tt>, or
+ * <tt>null</tt> if there was no mapping for <tt>definition</tt>.
+ */
+ public TypeDescription addTypeDescription(TypeDescription definition) {
+ if (definition == null) {
+ throw new NullPointerException("ClassDescription is required.");
+ }
+ String tag = definition.getTag();
+ classTags.put(definition.getType(), tag);
+ return classDefinitions.put(definition.getType(), definition);
+ }
+
+ private class RepresentJavaBean implements Represent {
+ public Node representData(Object data) {
+ Set<Property> properties;
+ try {
+ properties = getProperties(data.getClass());
+ } catch (IntrospectionException e) {
+ throw new YAMLException(e);
+ }
+ Node node = representMapping(properties, data);
+ return node;
+ }
+ }
+
+ private Node representMapping(Set<Property> properties, Object javaBean) {
+ List<Node[]> value = new LinkedList<Node[]>();
+ String tag;
+ String customTag = classTags.get(javaBean.getClass());
+ if (customTag == null) {
+ if (rootTag == null) {
+ tag = "tag:yaml.org,2002:" + javaBean.getClass().getName();
+ } else {
+ tag = "tag:yaml.org,2002:map";
+ }
+ } else {
+ tag = customTag;
+ }
+ if (rootTag == null) {
+ rootTag = tag;
+ }
+ // flow style will be chosen by BaseRepresenter
+ MappingNode node = new MappingNode(tag, value, null);
+ representedObjects.put(aliasKey, node);
+ boolean bestStyle = true;
+ for (Property property : properties) {
+ Node nodeKey = representData(property.getName());
+ Object memberValue = property.get(javaBean);
+ Node nodeValue = representData(memberValue);
+ if (nodeValue instanceof MappingNode) {
+ if (!Map.class.isAssignableFrom(memberValue.getClass())) {
+ if (property.getType() != memberValue.getClass()) {
+ String memberTag = "tag:yaml.org,2002:" + memberValue.getClass().getName();
+ nodeValue.setTag(memberTag);
+ }
+ }
+ } else if (memberValue != null && Enum.class.isAssignableFrom(memberValue.getClass())) {
+ nodeValue.setTag("tag:yaml.org,2002:str");
+ }
+ if (!((nodeKey instanceof ScalarNode && ((ScalarNode) nodeKey).getStyle() == null))) {
+ bestStyle = false;
+ }
+ if (!((nodeValue instanceof ScalarNode && ((ScalarNode) nodeValue).getStyle() == null))) {
+ bestStyle = false;
+ }
+ value.add(new Node[] { nodeKey, nodeValue });
+ }
+ if (defaultFlowStyle != null) {
+ node.setFlowStyle(defaultFlowStyle);
+ } else {
+ node.setFlowStyle(bestStyle);
+ }
+ return node;
+ }
+
+ private Set<Property> getProperties(Class<? extends Object> type) throws IntrospectionException {
+ Set<Property> properties = new TreeSet<Property>();
+ for (PropertyDescriptor property : Introspector.getBeanInfo(type).getPropertyDescriptors())
+ if (property.getReadMethod() != null
+ && !property.getReadMethod().getName().equals("getClass")) {
+ properties.add(new MethodProperty(property));
+ }
+ for (Field field : type.getFields()) {
+ int modifiers = field.getModifiers();
+ if (!Modifier.isPublic(modifiers) || Modifier.isStatic(modifiers)
+ || Modifier.isTransient(modifiers))
+ continue;
+ properties.add(new FieldProperty(field));
+ }
+ return properties;
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/representer/SafeRepresenter.java b/src/main/java/org/yaml/snakeyaml/representer/SafeRepresenter.java
new file mode 100644
index 00000000..77c4a8b2
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/representer/SafeRepresenter.java
@@ -0,0 +1,219 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.representer;
+
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TimeZone;
+import java.util.regex.Pattern;
+
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.util.Base64Coder;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+class SafeRepresenter extends BaseRepresenter {
+
+ public SafeRepresenter(Character default_style, Boolean default_flow_style) {
+ super(default_style, default_flow_style);
+ this.nullRepresenter = new RepresentNull();
+ this.representers.put(String.class, new RepresentString());
+ this.representers.put(Boolean.class, new RepresentBoolean());
+ this.representers.put(Character.class, new RepresentString());
+ this.representers.put(byte[].class, new RepresentByteArray());
+ this.multiRepresenters.put(Number.class, new RepresentNumber());
+ this.multiRepresenters.put(List.class, new RepresentList());
+ this.multiRepresenters.put(Map.class, new RepresentMap());
+ this.multiRepresenters.put(Set.class, new RepresentSet());
+ this.multiRepresenters.put(new Object[0].getClass(), new RepresentArray());
+ this.multiRepresenters.put(Date.class, new RepresentDate());
+ this.multiRepresenters.put(Enum.class, new RepresentEnum());
+ }
+
+ @Override
+ protected boolean ignoreAliases(Object data) {
+ if (data == null) {
+ return true;
+ }
+ if (data instanceof Object[]) {
+ Object[] array = (Object[]) data;
+ if (array.length == 0) {
+ return true;
+ }
+ }
+ return data instanceof String || data instanceof Boolean || data instanceof Integer
+ || data instanceof Long || data instanceof Float || data instanceof Double
+ || data instanceof Enum;
+ }
+
+ private class RepresentNull implements Represent {
+ public Node representData(Object data) {
+ return representScalar("tag:yaml.org,2002:null", "null");
+ }
+ }
+
+ public static Pattern BINARY_PATTERN = Pattern.compile("[\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F]");
+
+ private class RepresentString implements Represent {
+ public Node representData(Object data) {
+ String tag = "tag:yaml.org,2002:str";
+ Character style = null;
+ String value = data.toString();
+ if (BINARY_PATTERN.matcher(value).find()) {
+ tag = "tag:yaml.org,2002:binary";
+ char[] binary;
+ binary = Base64Coder.encode(value.getBytes());
+ value = String.valueOf(binary);
+ style = '|';
+ }
+ return representScalar(tag, value, style);
+ }
+ }
+
+ private class RepresentBoolean implements Represent {
+ public Node representData(Object data) {
+ String value;
+ if (Boolean.TRUE.equals(data)) {
+ value = "true";
+ } else {
+ value = "false";
+ }
+ return representScalar("tag:yaml.org,2002:bool", value);
+ }
+ }
+
+ private class RepresentNumber implements Represent {
+ public Node representData(Object data) {
+ String tag;
+ String value;
+ if (data instanceof Byte || data instanceof Short || data instanceof Integer
+ || data instanceof Long || data instanceof BigInteger) {
+ tag = "tag:yaml.org,2002:int";
+ value = data.toString();
+ } else {
+ Number number = (Number) data;
+ tag = "tag:yaml.org,2002:float";
+ if (number.equals(Double.NaN)) {
+ value = ".NaN";
+ } else if (number.equals(Double.POSITIVE_INFINITY)) {
+ value = ".inf";
+ } else if (number.equals(Double.NEGATIVE_INFINITY)) {
+ value = "-.inf";
+ } else {
+ value = number.toString();
+ }
+ }
+ return representScalar(tag, value);
+ }
+ }
+
+ private class RepresentList implements Represent {
+ @SuppressWarnings("unchecked")
+ public Node representData(Object data) {
+ return representSequence("tag:yaml.org,2002:seq", (List<Object>) data, null);
+ }
+ }
+
+ private class RepresentArray implements Represent {
+ public Node representData(Object data) {
+ Object[] array = (Object[]) data;
+ List<Object> list = Arrays.asList(array);
+ return representSequence("tag:yaml.org,2002:seq", list, null);
+ }
+ }
+
+ private class RepresentMap implements Represent {
+ @SuppressWarnings("unchecked")
+ public Node representData(Object data) {
+ return representMapping("tag:yaml.org,2002:map", (Map<Object, Object>) data, null);
+ }
+ }
+
+ private class RepresentSet implements Represent {
+ @SuppressWarnings("unchecked")
+ public Node representData(Object data) {
+ Map<Object, Object> value = new LinkedHashMap<Object, Object>();
+ Set<Object> set = (Set<Object>) data;
+ for (Object key : set) {
+ value.put(key, null);
+ }
+ return representMapping("tag:yaml.org,2002:set", value, null);
+ }
+ }
+
+ private class RepresentDate implements Represent {
+ public Node representData(Object data) {
+ // because SimpleDateFormat ignores timezone we have to use Calendar
+ Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
+ calendar.setTime((Date) data);
+ int years = calendar.get(Calendar.YEAR);
+ int months = calendar.get(Calendar.MONTH) + 1; // 0..12
+ int days = calendar.get(Calendar.DAY_OF_MONTH); // 1..31
+ int hour24 = calendar.get(Calendar.HOUR_OF_DAY); // 0..24
+ int minutes = calendar.get(Calendar.MINUTE); // 0..59
+ int seconds = calendar.get(Calendar.SECOND); // 0..59
+ int millis = calendar.get(Calendar.MILLISECOND);
+ StringBuffer buffer = new StringBuffer(String.valueOf(years));
+ buffer.append("-");
+ if (months < 10) {
+ buffer.append("0");
+ }
+ buffer.append(String.valueOf(months));
+ buffer.append("-");
+ if (days < 10) {
+ buffer.append("0");
+ }
+ buffer.append(String.valueOf(days));
+ buffer.append("T");
+ if (hour24 < 10) {
+ buffer.append("0");
+ }
+ buffer.append(String.valueOf(hour24));
+ buffer.append(":");
+ if (minutes < 10) {
+ buffer.append("0");
+ }
+ buffer.append(String.valueOf(minutes));
+ buffer.append(":");
+ if (seconds < 10) {
+ buffer.append("0");
+ }
+ buffer.append(String.valueOf(seconds));
+ if (millis > 0) {
+ if (millis < 10) {
+ buffer.append(".00");
+ } else if (millis < 100) {
+ buffer.append(".0");
+ } else {
+ buffer.append(".");
+ }
+ buffer.append(String.valueOf(millis));
+ }
+ buffer.append("Z");
+ return representScalar("tag:yaml.org,2002:timestamp", buffer.toString(), null);
+ }
+ }
+
+ private class RepresentEnum implements Represent {
+ public Node representData(Object data) {
+ String tag = "tag:yaml.org,2002:" + data.getClass().getName();
+ return representScalar(tag, data.toString());
+ }
+ }
+
+ private class RepresentByteArray implements Represent {
+ public Node representData(Object data) {
+ String tag = "tag:yaml.org,2002:binary";
+ char[] binary = Base64Coder.encode((byte[]) data);
+ return representScalar(tag, String.valueOf(binary), '|');
+ }
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/yaml/snakeyaml/resolver/RagelMachine.rl b/src/main/java/org/yaml/snakeyaml/resolver/RagelMachine.rl
new file mode 100644
index 00000000..4a084426
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/resolver/RagelMachine.rl
@@ -0,0 +1,81 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.resolver;
+//Source for Ragel 6.3
+
+/**
+ * Generated by Ragel 6.3 (http://www.complang.org/ragel/)
+ * @see http://www.complang.org/ragel/
+ */
+public class RagelMachine {
+ %%{
+ machine snakeyaml;
+ action bool_tag { tag = "tag:yaml.org,2002:bool"; }
+ action merge_tag { tag = "tag:yaml.org,2002:merge"; }
+ action null_tag { tag = "tag:yaml.org,2002:null"; }
+ action value_tag { tag = "tag:yaml.org,2002:value"; }
+ action int_tag { tag = "tag:yaml.org,2002:int"; }
+ action float_tag { tag = "tag:yaml.org,2002:float"; }
+ action timestamp_tag { tag = "tag:yaml.org,2002:timestamp"; }
+
+ Bool = ("yes" | "Yes" | "YES" | "no" | "No" | "NO" |
+ "true" | "True" | "TRUE" | "false" | "False" | "FALSE" |
+ "on" | "On" | "ON" | "off" | "Off" | "OFF") %/bool_tag;
+ Merge = "<<" %/merge_tag;
+ Value = "=" %/value_tag;
+ Null = ("~" | "null" | "Null" | "NULL" | " ") %/null_tag;
+
+ sign = "-" | "+";
+ digit2 = digit | "_";
+ binaryInt = "0b" [0-1_]+;
+ octalInt = "0" [0-7_]+;
+ decimalInt = "0" | [1-9]digit2* (":" [0-5]? digit)*;
+ hexaInt = "0x" [0-9a-fA-F_]+;
+ Int = sign? (binaryInt | octalInt | decimalInt | hexaInt) %/int_tag;
+
+ exp = [eE] sign digit+;
+ Float = ((sign? ((digit+ digit2* "." digit2* exp?)
+ | ((digit+ digit2*)? "." digit+ digit2* exp?)
+ | (digit+ (":" [0-5]? digit)+ "." digit*)
+ | "." ("inf" | "Inf" | "INF")))
+ | ("." ("nan" | "NaN" | "NAN"))) %/float_tag;
+
+ TimestampShort = digit{4} ("-" digit{2}){2} %/timestamp_tag;
+ fract = "." digit*;
+ zone = [ \t]* ("Z" | (sign digit{1,2} ( ":" digit{2} )?));
+ Timestamp = digit{4} ("-" digit{1,2}){2} ([Tt] | [ \t]+)
+ digit{1,2} ":" digit{2} ":" digit{2} fract? zone? %/timestamp_tag;
+
+ Scalar = Bool | Null | Int | Float | TimestampShort | Merge | Value | Timestamp;
+ main := Scalar;
+ write data nofinal;
+ }%%
+
+ public String scan(String scalar) {
+ if (scalar == null) {
+ throw new NullPointerException("Scalar must be provided.");
+ }
+ String tag = null;
+ int cs = 0;
+ int p = 0;
+ int pe = scalar.length();
+ int eof = pe;
+ char[] data;
+ if (pe == 0) {
+ // NULL value
+ data = new char[] { '~' };
+ pe = 1;
+ eof = 1;
+ } else {
+ data = scalar.toCharArray();
+ }
+ %%{
+ # Initialize and execute.
+ write init;
+ write exec;
+ }%%
+
+ return tag;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/yaml/snakeyaml/resolver/Resolver.java b/src/main/java/org/yaml/snakeyaml/resolver/Resolver.java
new file mode 100644
index 00000000..2f578d04
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/resolver/Resolver.java
@@ -0,0 +1,114 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.resolver;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+import org.yaml.snakeyaml.nodes.NodeId;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public class Resolver {
+ private static final String DEFAULT_SCALAR_TAG = "tag:yaml.org,2002:str";
+ private static final String DEFAULT_SEQUENCE_TAG = "tag:yaml.org,2002:seq";
+ private static final String DEFAULT_MAPPING_TAG = "tag:yaml.org,2002:map";
+ private static final Pattern BOOL = Pattern
+ .compile("^(?:yes|Yes|YES|no|No|NO|true|True|TRUE|false|False|FALSE|on|On|ON|off|Off|OFF)$");
+ private static final Pattern FLOAT = Pattern
+ .compile("^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?|[-+]?(?:[0-9][0-9_]*)?\\.[0-9_]+(?:[eE][-+][0-9]+)?|[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*|[-+]?\\.(?:inf|Inf|INF)|\\.(?:nan|NaN|NAN))$");
+ private static final Pattern INT = Pattern
+ .compile("^(?:[-+]?0b[0-1_]+|[-+]?0[0-7_]+|[-+]?(?:0|[1-9][0-9_]*)|[-+]?0x[0-9a-fA-F_]+|[-+]?[1-9][0-9_]*(?::[0-5]?[0-9])+)$");
+ private static final Pattern MERGE = Pattern.compile("^(?:<<)$");
+ private static final Pattern NULL = Pattern.compile("^(?:~|null|Null|NULL| )$");
+ private static final Pattern EMPTY = Pattern.compile("^$");
+ private static final Pattern TIMESTAMP = Pattern
+ .compile("^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]|[0-9][0-9][0-9][0-9]-[0-9][0-9]?-[0-9][0-9]?(?:[Tt]|[ \t]+)[0-9][0-9]?:[0-9][0-9]:[0-9][0-9](?:\\.[0-9]*)?(?:[ \t]*(?:Z|[-+][0-9][0-9]?(?::[0-9][0-9])?))?)$");
+ private static final Pattern VALUE = Pattern.compile("^(?:=)$");
+ private static final Pattern YAML = Pattern.compile("^(?:!|&|\\*)$");
+
+ private Map<Character, List<ResolverTuple>> yamlImplicitResolvers = new HashMap<Character, List<ResolverTuple>>();
+
+ public Resolver() {
+ addImplicitResolver("tag:yaml.org,2002:bool", BOOL, "yYnNtTfFoO");
+ addImplicitResolver("tag:yaml.org,2002:float", FLOAT, "-+0123456789.");
+ addImplicitResolver("tag:yaml.org,2002:int", INT, "-+0123456789");
+ addImplicitResolver("tag:yaml.org,2002:merge", MERGE, "<");
+ addImplicitResolver("tag:yaml.org,2002:null", NULL, "~nN\0");
+ addImplicitResolver("tag:yaml.org,2002:null", EMPTY, null);
+ addImplicitResolver("tag:yaml.org,2002:timestamp", TIMESTAMP, "0123456789");
+ addImplicitResolver("tag:yaml.org,2002:value", VALUE, "=");
+ // The following implicit resolver is only for documentation purposes.
+ // It cannot work
+ // because plain scalars cannot start with '!', '&', or '*'.
+ addImplicitResolver("tag:yaml.org,2002:yaml", YAML, "!&*");
+ }
+
+ public void addImplicitResolver(String tag, Pattern regexp, String first) {
+ if (first == null) {
+ List<ResolverTuple> curr = yamlImplicitResolvers.get(null);
+ if (curr == null) {
+ curr = new LinkedList<ResolverTuple>();
+ yamlImplicitResolvers.put(null, curr);
+ }
+ curr.add(new ResolverTuple(tag, regexp));
+ } else {
+ char[] chrs = first.toCharArray();
+ for (int i = 0, j = chrs.length; i < j; i++) {
+ Character theC = new Character(chrs[i]);
+ if (theC == 0) {
+ // special case: for null
+ theC = null;
+ }
+ List<ResolverTuple> curr = yamlImplicitResolvers.get(theC);
+ if (curr == null) {
+ curr = new LinkedList<ResolverTuple>();
+ yamlImplicitResolvers.put(theC, curr);
+ }
+ curr.add(new ResolverTuple(tag, regexp));
+ }
+ }
+ }
+
+ public String resolve(NodeId kind, String value, boolean implicit) {
+ if (kind == NodeId.scalar && implicit) {
+ List<ResolverTuple> resolvers = null;
+ if ("".equals(value)) {
+ resolvers = yamlImplicitResolvers.get('\0');
+ } else {
+ resolvers = yamlImplicitResolvers.get(value.charAt(0));
+ }
+ if (resolvers != null) {
+ for (ResolverTuple v : resolvers) {
+ String tag = v.getTag();
+ Pattern regexp = v.getRegexp();
+ if (regexp.matcher(value).matches()) {
+ return tag;
+ }
+ }
+ }
+ if (yamlImplicitResolvers.containsKey(null)) {
+ for (ResolverTuple v : yamlImplicitResolvers.get(null)) {
+ String tag = v.getTag();
+ Pattern regexp = v.getRegexp();
+ if (regexp.matcher(value).matches()) {
+ return tag;
+ }
+ }
+ }
+ }
+ switch (kind) {
+ case scalar:
+ return DEFAULT_SCALAR_TAG;
+ case sequence:
+ return DEFAULT_SEQUENCE_TAG;
+ default:
+ return DEFAULT_MAPPING_TAG;
+ }
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/yaml/snakeyaml/resolver/ResolverTuple.java b/src/main/java/org/yaml/snakeyaml/resolver/ResolverTuple.java
new file mode 100644
index 00000000..239e51ae
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/resolver/ResolverTuple.java
@@ -0,0 +1,29 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.resolver;
+
+import java.util.regex.Pattern;
+
+final class ResolverTuple {
+ private final String tag;
+ private final Pattern regexp;
+
+ public ResolverTuple(String tag, Pattern regexp) {
+ this.tag = tag;
+ this.regexp = regexp;
+ }
+
+ public String getTag() {
+ return tag;
+ }
+
+ public Pattern getRegexp() {
+ return regexp;
+ }
+
+ @Override
+ public String toString() {
+ return "Tuple tag=" + tag + " regexp=" + regexp;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/yaml/snakeyaml/scanner/Scanner.java b/src/main/java/org/yaml/snakeyaml/scanner/Scanner.java
new file mode 100644
index 00000000..6ed91ab8
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/scanner/Scanner.java
@@ -0,0 +1,36 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.scanner;
+
+import java.util.List;
+
+import org.yaml.snakeyaml.tokens.Token;
+
+/**
+ * Produce <code>Token<code>s.
+ *
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public interface Scanner {
+ /**
+ * Check if the next token is one of the given types.
+ */
+ boolean checkToken(List<Class<? extends Token>> choices);
+
+ /**
+ * Convenience method to avoid List creation
+ */
+ boolean checkToken(Class<? extends Token> choice);
+
+ /**
+ * Return the next token, but do not delete it from the queue.
+ */
+ Token peekToken();
+
+ /**
+ * Return the next token.
+ */
+ Token getToken();
+
+}
diff --git a/src/main/java/org/yaml/snakeyaml/scanner/ScannerException.java b/src/main/java/org/yaml/snakeyaml/scanner/ScannerException.java
new file mode 100644
index 00000000..3dbae586
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/scanner/ScannerException.java
@@ -0,0 +1,25 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.scanner;
+
+import org.yaml.snakeyaml.error.Mark;
+import org.yaml.snakeyaml.error.MarkedYAMLException;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public class ScannerException extends MarkedYAMLException {
+
+ private static final long serialVersionUID = 4782293188600445954L;
+
+ public ScannerException(String context, Mark contextMark, String problem, Mark problemMark,
+ String note) {
+ super(context, contextMark, problem, problemMark, note);
+ }
+
+ public ScannerException(String context, Mark contextMark, String problem, Mark problemMark) {
+ super(context, contextMark, problem, problemMark, null);
+ }
+
+}
diff --git a/src/main/java/org/yaml/snakeyaml/scanner/ScannerImpl.java b/src/main/java/org/yaml/snakeyaml/scanner/ScannerImpl.java
new file mode 100644
index 00000000..9941ce73
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/scanner/ScannerImpl.java
@@ -0,0 +1,1757 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.scanner;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+import org.yaml.snakeyaml.error.Mark;
+import org.yaml.snakeyaml.error.YAMLException;
+import org.yaml.snakeyaml.tokens.AliasToken;
+import org.yaml.snakeyaml.tokens.AnchorToken;
+import org.yaml.snakeyaml.tokens.BlockEndToken;
+import org.yaml.snakeyaml.tokens.BlockEntryToken;
+import org.yaml.snakeyaml.tokens.BlockMappingStartToken;
+import org.yaml.snakeyaml.tokens.BlockSequenceStartToken;
+import org.yaml.snakeyaml.tokens.DirectiveToken;
+import org.yaml.snakeyaml.tokens.DocumentEndToken;
+import org.yaml.snakeyaml.tokens.DocumentStartToken;
+import org.yaml.snakeyaml.tokens.FlowEntryToken;
+import org.yaml.snakeyaml.tokens.FlowMappingEndToken;
+import org.yaml.snakeyaml.tokens.FlowMappingStartToken;
+import org.yaml.snakeyaml.tokens.FlowSequenceEndToken;
+import org.yaml.snakeyaml.tokens.FlowSequenceStartToken;
+import org.yaml.snakeyaml.tokens.KeyToken;
+import org.yaml.snakeyaml.tokens.ScalarToken;
+import org.yaml.snakeyaml.tokens.StreamEndToken;
+import org.yaml.snakeyaml.tokens.StreamStartToken;
+import org.yaml.snakeyaml.tokens.TagToken;
+import org.yaml.snakeyaml.tokens.Token;
+import org.yaml.snakeyaml.tokens.ValueToken;
+
+/**
+ * <pre>
+ * Scanner produces tokens of the following types:
+ * STREAM-START
+ * STREAM-END
+ * DIRECTIVE(name, value)
+ * DOCUMENT-START
+ * DOCUMENT-END
+ * BLOCK-SEQUENCE-START
+ * BLOCK-MAPPING-START
+ * BLOCK-END
+ * FLOW-SEQUENCE-START
+ * FLOW-MAPPING-START
+ * FLOW-SEQUENCE-END
+ * FLOW-MAPPING-END
+ * BLOCK-ENTRY
+ * FLOW-ENTRY
+ * KEY
+ * VALUE
+ * ALIAS(value)
+ * ANCHOR(value)
+ * TAG(value)
+ * SCALAR(value, plain, style)
+ * Read comments in the Scanner code for more details.
+ * </pre>
+ *
+ * Reader does the dirty work of checking for BOM and converting the input data
+ * to Unicode. It also adds NUL to the end.
+ *
+ * Reader supports the following methods
+ *
+ * <pre>
+ * reader.peek(i=0) # peek the next i-th character self.prefix(l=1)
+ * reader.peek the next l characters
+ * reader.forward(l=1) read the next l characters and move the pointer.
+ * </pre>
+ */
+public final class ScannerImpl implements Scanner {
+ private final static String NULL_BL_LINEBR = "\0 \r\n\u0085\u2028\u2029";
+ private final static String NULL_BL_T_LINEBR = "\0 \t\r\n\u0085\u2028\u2029";
+ public final static String NULL_OR_LINEBR = "\0\r\n\u0085\u2028\u2029";
+ private final static String FULL_LINEBR = "\r\n\u0085\u2028\u2029";
+ private final static String ALPHA = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-_";
+ private final static Pattern NOT_HEXA = Pattern.compile("[^0-9A-Fa-f]");
+ public final static Map<Character, String> ESCAPE_REPLACEMENTS = new HashMap<Character, String>();
+ public final static Map<Character, Integer> ESCAPE_CODES = new HashMap<Character, Integer>();
+
+ static {
+ ESCAPE_REPLACEMENTS.put(new Character('0'), "\0");
+ ESCAPE_REPLACEMENTS.put(new Character('a'), "\u0007");
+ ESCAPE_REPLACEMENTS.put(new Character('b'), "\u0008");
+ ESCAPE_REPLACEMENTS.put(new Character('t'), "\u0009");
+ ESCAPE_REPLACEMENTS.put(new Character('n'), "\n");
+ ESCAPE_REPLACEMENTS.put(new Character('v'), "\u000B");
+ ESCAPE_REPLACEMENTS.put(new Character('f'), "\u000C");
+ ESCAPE_REPLACEMENTS.put(new Character('r'), "\r");
+ ESCAPE_REPLACEMENTS.put(new Character('e'), "\u001B");
+ ESCAPE_REPLACEMENTS.put(new Character(' '), "\u0020");
+ ESCAPE_REPLACEMENTS.put(new Character('"'), "\"");
+ ESCAPE_REPLACEMENTS.put(new Character('\\'), "\\");
+ ESCAPE_REPLACEMENTS.put(new Character('N'), "\u0085");
+ ESCAPE_REPLACEMENTS.put(new Character('_'), "\u00A0");
+ ESCAPE_REPLACEMENTS.put(new Character('L'), "\u2028");
+ ESCAPE_REPLACEMENTS.put(new Character('P'), "\u2029");
+
+ ESCAPE_CODES.put(new Character('x'), new Integer(2));
+ ESCAPE_CODES.put(new Character('u'), new Integer(4));
+ ESCAPE_CODES.put(new Character('U'), new Integer(8));
+ }
+ private final org.yaml.snakeyaml.reader.Reader reader;
+ // Had we reached the end of the stream?
+ private boolean done = false;
+
+ // The number of unclosed '{' and '['. `flow_level == 0` means block
+ // context.
+ private int flowLevel = 0;
+
+ // List of processed tokens that are not yet emitted.
+ private List<Token> tokens;
+
+ // Number of tokens that were emitted through the `get_token` method.
+ private int tokensTaken = 0;
+
+ // The current indentation level.
+ private int indent = -1;
+
+ // Past indentation levels.
+ private LinkedList<Integer> indents;
+
+ // Variables related to simple keys treatment. See PyYAML.
+
+ /**
+ * <pre>
+ * A simple key is a key that is not denoted by the '?' indicator.
+ * Example of simple keys:
+ * ---
+ * block simple key: value
+ * ? not a simple key:
+ * : { flow simple key: value }
+ * We emit the KEY token before all keys, so when we find a potential
+ * simple key, we try to locate the corresponding ':' indicator.
+ * Simple keys should be limited to a single line and 1024 characters.
+ *
+ * Can a simple key start at the current position? A simple key may
+ * start:
+ * - at the beginning of the line, not counting indentation spaces
+ * (in block context),
+ * - after '{', '[', ',' (in the flow context),
+ * - after '?', ':', '-' (in the block context).
+ * In the block context, this flag also signifies if a block collection
+ * may start at the current position.
+ * </pre>
+ */
+ private boolean allowSimpleKey = true;
+
+ /*
+ * Keep track of possible simple keys. This is a dictionary. The key is
+ * `flow_level`; there can be no more that one possible simple key for each
+ * level. The value is a SimpleKey record: (token_number, required, index,
+ * line, column, mark) A simple key may start with ALIAS, ANCHOR, TAG,
+ * SCALAR(flow), '[', or '{' tokens.
+ */
+ private Map<Integer, SimpleKey> possibleSimpleKeys;
+
+ public ScannerImpl(org.yaml.snakeyaml.reader.Reader reader) {
+ this.reader = reader;
+ this.tokens = new LinkedList<Token>();
+ this.indents = new LinkedList<Integer>();
+ // the order in possibleSimpleKeys is kept for nextPossibleSimpleKey()
+ this.possibleSimpleKeys = new LinkedHashMap<Integer, SimpleKey>();
+ fetchStreamStart();// Add the STREAM-START token.
+ }
+
+ /**
+ * Check if the next token is one of the given types.
+ */
+ public boolean checkToken(List<Class<? extends Token>> choices) {
+ while (needMoreTokens()) {
+ fetchMoreTokens();
+ }
+ if (!this.tokens.isEmpty()) {
+ if (choices.size() == 0) {
+ return true;
+ }
+ Token first = this.tokens.get(0);
+ for (Class<? extends Token> class1 : choices) {
+ if (class1.isInstance(first)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Check if the next token is one of the given types.
+ */
+ public boolean checkToken(Class<? extends Token> choice) {
+ List<Class<? extends Token>> list = new ArrayList<Class<? extends Token>>();
+ list.add(choice);
+ return checkToken(list);
+ }
+
+ /**
+ * Return the next token, but do not delete if from the queue.
+ */
+ public Token peekToken() {
+ while (needMoreTokens()) {
+ fetchMoreTokens();
+ }
+ return this.tokens.get(0);
+ }
+
+ /**
+ * Return the next token.
+ */
+ public Token getToken() {
+ if (!this.tokens.isEmpty()) {
+ this.tokensTaken++;
+ return this.tokens.remove(0);
+ }
+ return null;
+ }
+
+ // Private methods.
+
+ private boolean needMoreTokens() {
+ if (this.done) {
+ return false;
+ }
+ if (this.tokens.isEmpty()) {
+ return true;
+ }
+ // The current token may be a potential simple key, so we
+ // need to look further.
+ stalePossibleSimpleKeys();
+ return nextPossibleSimpleKey() == this.tokensTaken;
+ }
+
+ private void fetchMoreTokens() {
+ // Eat whitespaces and comments until we reach the next token.
+ scanToNextToken();
+ // Remove obsolete possible simple keys.
+ stalePossibleSimpleKeys();
+ // Compare the current indentation and column. It may add some tokens
+ // and decrease the current indentation level.
+ unwindIndent(reader.getColumn());
+ // Peek the next character.
+ char ch = reader.peek();
+ switch (ch) {
+ case '\0':
+ // Is it the end of stream?
+ fetchStreamEnd();
+ return;
+ case '%':
+ // Is it a directive?
+ if (checkDirective()) {
+ fetchDirective();
+ return;
+ }
+ break;
+ case '-':
+ // Is it the document start?
+ if (checkDocumentStart()) {
+ fetchDocumentStart();
+ return;
+ // Is it the block entry indicator?
+ } else if (checkBlockEntry()) {
+ fetchBlockEntry();
+ return;
+ }
+ break;
+ case '.':
+ // Is it the document end?
+ if (checkDocumentEnd()) {
+ fetchDocumentEnd();
+ return;
+ }
+ break;
+ // TODO support for BOM within a stream. (not implemented in PyYAML)
+ case '[':
+ // Is it the flow sequence start indicator?
+ fetchFlowSequenceStart();
+ return;
+ case '{':
+ // Is it the flow mapping start indicator?
+ fetchFlowMappingStart();
+ return;
+ case ']':
+ // Is it the flow sequence end indicator?
+ fetchFlowSequenceEnd();
+ return;
+ case '}':
+ // Is it the flow mapping end indicator?
+ fetchFlowMappingEnd();
+ return;
+ case ',':
+ // Is it the flow entry indicator?
+ fetchFlowEntry();
+ return;
+ // see block entry indicator above
+ case '?':
+ // Is it the key indicator?
+ if (checkKey()) {
+ fetchKey();
+ return;
+ }
+ break;
+ case ':':
+ // Is it the value indicator?
+ if (checkValue()) {
+ fetchValue();
+ return;
+ }
+ break;
+ case '*':
+ // Is it an alias?
+ fetchAlias();
+ return;
+ case '&':
+ // Is it an anchor?
+ fetchAnchor();
+ return;
+ case '!':
+ // Is it a tag?
+ fetchTag();
+ return;
+ case '|':
+ // Is it a literal scalar?
+ if (this.flowLevel == 0) {
+ fetchLiteral();
+ return;
+ }
+ break;
+ case '>':
+ // Is it a folded scalar?
+ if (this.flowLevel == 0) {
+ fetchFolded();
+ return;
+ }
+ break;
+ case '\'':
+ // Is it a single quoted scalar?
+ fetchSingle();
+ return;
+ case '"':
+ // Is it a double quoted scalar?
+ fetchDouble();
+ return;
+ }
+ // It must be a plain scalar then.
+ if (checkPlain()) {
+ fetchPlain();
+ return;
+ }
+ // No? It's an error. Let's produce a nice error message.
+ throw new ScannerException("while scanning for the next token", null, "found character "
+ + ch + "(" + ((int) ch) + " that cannot start any token", reader.getMark());
+ }
+
+ // Simple keys treatment.
+
+ /**
+ * Return the number of the nearest possible simple key. Actually we don't
+ * need to loop through the whole dictionary.
+ */
+ private int nextPossibleSimpleKey() {
+ /*
+ * the implementation is not as in PyYAML. Because
+ * this.possibleSimpleKeys is ordered we can simply take the first key
+ */
+ Iterator<SimpleKey> iter = this.possibleSimpleKeys.values().iterator();
+ if (iter.hasNext()) {
+ SimpleKey key = iter.next();
+ return key.getTokenNumber();
+ }
+ return -1;
+ }
+
+ /**
+ * <pre>
+ * Remove entries that are no longer possible simple keys. According to
+ * the YAML specification, simple keys
+ * - should be limited to a single line,
+ * - should be no longer than 1024 characters.
+ * Disabling this procedure will allow simple keys of any length and
+ * height (may cause problems if indentation is broken though).
+ * </pre>
+ */
+ private void stalePossibleSimpleKeys() {
+ // use toRemove to avoid java.util.ConcurrentModificationException
+ Set<Integer> toRemove = null;
+ for (Integer level : this.possibleSimpleKeys.keySet()) {
+ SimpleKey key = this.possibleSimpleKeys.get(level);
+ if ((key.getLine() != reader.getLine()) || (reader.getIndex() - key.getIndex() > 1024)) {
+ if (key.isRequired()) {
+ throw new ScannerException("while scanning a simple key", key.getMark(),
+ "could not found expected ':'", reader.getMark());
+ } else {
+ if (toRemove == null) {
+ toRemove = new HashSet<Integer>();
+ }
+ toRemove.add(level);
+ }
+ }
+ }
+ if (toRemove != null) {
+ for (Integer level : toRemove) {
+ this.possibleSimpleKeys.remove(level);
+ }
+ }
+ }
+
+ /**
+ * The next token may start a simple key. We check if it's possible and save
+ * its position. This function is called for ALIAS, ANCHOR, TAG,
+ * SCALAR(flow), '[', and '{'.
+ */
+ private void savePossibleSimpleKey() {
+ // The next token may start a simple key. We check if it's possible
+ // and save its position. This function is called for
+ // ALIAS, ANCHOR, TAG, SCALAR(flow), '[', and '{'.
+
+ // Check if a simple key is required at the current position.
+ boolean required = ((this.flowLevel == 0) && (this.indent == this.reader.getColumn()));
+
+ if (allowSimpleKey || !required) {
+ // A simple key is required only if it is the first token in the
+ // current
+ // line. Therefore it is always allowed.
+ } else {
+ throw new YAMLException(
+ "A simple key is required only if it is the first token in the current line");
+ }
+
+ // The next token might be a simple key. Let's save it's number and
+ // position.
+ if (this.allowSimpleKey) {
+ removePossibleSimpleKey();
+ int tokenNumber = this.tokensTaken + this.tokens.size();
+ SimpleKey key = new SimpleKey(tokenNumber, required, reader.getIndex(), reader
+ .getLine(), this.reader.getColumn(), this.reader.getMark());
+ this.possibleSimpleKeys.put(new Integer(this.flowLevel), key);
+ }
+ }
+
+ /**
+ * Remove the saved possible key position at the current flow level.
+ */
+ private void removePossibleSimpleKey() {
+ if (this.possibleSimpleKeys.keySet().contains(new Integer(flowLevel))) {
+ SimpleKey key = possibleSimpleKeys.get(new Integer(flowLevel));
+ if (key.isRequired()) {
+ throw new ScannerException("while scanning a simple key", key.getMark(),
+ "could not found expected ':'", reader.getMark());
+ }
+ possibleSimpleKeys.remove(flowLevel);
+ }
+ }
+
+ // Indentation functions.
+
+ /**
+ * <pre>
+ * In flow context, tokens should respect indentation.
+ * Actually the condition should be `self.indent &gt;= column` according to
+ * the spec. But this condition will prohibit intuitively correct
+ * constructions such as
+ * key : {
+ * }
+ * </pre>
+ */
+ private void unwindIndent(int col) {
+ // In the flow context, indentation is ignored. We make the scanner less
+ // restrictive then specification requires.
+ if (this.flowLevel != 0) {
+ return;
+ }
+
+ // In block context, we may need to issue the BLOCK-END tokens.
+ while (this.indent > col) {
+ Mark mark = reader.getMark();
+ this.indent = this.indents.removeFirst();
+ this.tokens.add(new BlockEndToken(mark, mark));
+ }
+ }
+
+ /**
+ * Check if we need to increase indentation.
+ */
+ private boolean addIndent(int column) {
+ if (this.indent < column) {
+ this.indents.addFirst(this.indent);
+ this.indent = column;
+ return true;
+ }
+ return false;
+ }
+
+ // Fetchers.
+
+ /**
+ * We always add STREAM-START as the first token and STREAM-END as the last
+ * token.
+ */
+ private void fetchStreamStart() {
+ // Read the token.
+ Mark mark = reader.getMark();
+
+ // Add STREAM-START.
+ Token token = new StreamStartToken(mark, mark);
+ this.tokens.add(token);
+ }
+
+ private void fetchStreamEnd() {
+ // Set the current intendation to -1.
+ unwindIndent(-1);
+
+ // Reset everything (not really needed).
+ this.allowSimpleKey = false;
+ this.possibleSimpleKeys = new HashMap<Integer, SimpleKey>();
+
+ // Read the token.
+ Mark mark = reader.getMark();
+
+ // Add STREAM-END.
+ Token token = new StreamEndToken(mark, mark);
+ this.tokens.add(token);
+
+ // The stream is finished.
+ this.done = true;
+ }
+
+ private void fetchDirective() {
+ // Set the current intendation to -1.
+ unwindIndent(-1);
+
+ // Reset simple keys.
+ removePossibleSimpleKey();
+ this.allowSimpleKey = false;
+
+ // Scan and add DIRECTIVE.
+ Token tok = scanDirective();
+ this.tokens.add(tok);
+ }
+
+ private void fetchDocumentStart() {
+ fetchDocumentIndicator(true);
+ }
+
+ private void fetchDocumentEnd() {
+ fetchDocumentIndicator(false);
+ }
+
+ private void fetchDocumentIndicator(boolean isDocumentStart) {
+ // Set the current intendation to -1.
+ unwindIndent(-1);
+
+ // Reset simple keys. Note that there could not be a block collection
+ // after '---'.
+ removePossibleSimpleKey();
+ this.allowSimpleKey = false;
+
+ // Add DOCUMENT-START or DOCUMENT-END.
+ Mark startMark = reader.getMark();
+ reader.forward(3);
+ Mark endMark = reader.getMark();
+ Token token;
+ if (isDocumentStart) {
+ token = new DocumentStartToken(startMark, endMark);
+ } else {
+ token = new DocumentEndToken(startMark, endMark);
+ }
+ this.tokens.add(token);
+ }
+
+ private void fetchFlowSequenceStart() {
+ fetchFlowCollectionStart(false);
+ }
+
+ private void fetchFlowMappingStart() {
+ fetchFlowCollectionStart(true);
+ }
+
+ private void fetchFlowCollectionStart(boolean isMappingStart) {
+ // '[' and '{' may start a simple key.
+ savePossibleSimpleKey();
+
+ // Increase the flow level.
+ this.flowLevel++;
+
+ // Simple keys are allowed after '[' and '{'.
+ this.allowSimpleKey = true;
+
+ // Add FLOW-SEQUENCE-START or FLOW-MAPPING-START.
+ Mark startMark = reader.getMark();
+ reader.forward(1);
+ Mark endMark = reader.getMark();
+ Token token;
+ if (isMappingStart) {
+ token = new FlowMappingStartToken(startMark, endMark);
+ } else {
+ token = new FlowSequenceStartToken(startMark, endMark);
+ }
+ this.tokens.add(token);
+ }
+
+ private void fetchFlowSequenceEnd() {
+ fetchFlowCollectionEnd(false);
+ }
+
+ private void fetchFlowMappingEnd() {
+ fetchFlowCollectionEnd(true);
+ }
+
+ private void fetchFlowCollectionEnd(boolean isMappingEnd) {
+ // Reset possible simple key on the current level.
+ removePossibleSimpleKey();
+
+ // Decrease the flow level.
+ this.flowLevel--;
+
+ // No simple keys after ']' or '}'.
+ this.allowSimpleKey = false;
+
+ // Add FLOW-SEQUENCE-END or FLOW-MAPPING-END.
+ Mark startMark = reader.getMark();
+ reader.forward();
+ Mark endMark = reader.getMark();
+ Token token;
+ if (isMappingEnd) {
+ token = new FlowMappingEndToken(startMark, endMark);
+ } else {
+ token = new FlowSequenceEndToken(startMark, endMark);
+ }
+ this.tokens.add(token);
+ }
+
+ private void fetchFlowEntry() {
+ // Simple keys are allowed after ','.
+ this.allowSimpleKey = true;
+
+ // Reset possible simple key on the current level.
+ removePossibleSimpleKey();
+
+ // Add FLOW-ENTRY.
+ Mark startMark = reader.getMark();
+ reader.forward();
+ Mark endMark = reader.getMark();
+ Token token = new FlowEntryToken(startMark, endMark);
+ this.tokens.add(token);
+ }
+
+ private void fetchBlockEntry() {
+ // Block context needs additional checks.
+ if (this.flowLevel == 0) {
+ // Are we allowed to start a new entry?
+ if (!this.allowSimpleKey) {
+ throw new ScannerException(null, null, "sequence entries are not allowed here",
+ reader.getMark());
+ }
+
+ // We may need to add BLOCK-SEQUENCE-START.
+ if (addIndent(this.reader.getColumn())) {
+ Mark mark = reader.getMark();
+ this.tokens.add(new BlockSequenceStartToken(mark, mark));
+ }
+ } else {
+ // It's an error for the block entry to occur in the flow
+ // context,but we let the parser detect this.
+ }
+ // Simple keys are allowed after '-'.
+ this.allowSimpleKey = true;
+
+ // Reset possible simple key on the current level.
+ removePossibleSimpleKey();
+
+ // Add BLOCK-ENTRY.
+ Mark startMark = reader.getMark();
+ reader.forward();
+ Mark endMark = reader.getMark();
+ Token token = new BlockEntryToken(startMark, endMark);
+ this.tokens.add(token);
+ }
+
+ private void fetchKey() {
+ // Block context needs additional checks.
+ if (this.flowLevel == 0) {
+ // Are we allowed to start a key (not necessary a simple)?
+ if (!this.allowSimpleKey) {
+ throw new ScannerException(null, null, "mapping keys are not allowed here", reader
+ .getMark());
+ }
+ // We may need to add BLOCK-MAPPING-START.
+ if (addIndent(this.reader.getColumn())) {
+ Mark mark = reader.getMark();
+ this.tokens.add(new BlockMappingStartToken(mark, mark));
+ }
+ }
+ // Simple keys are allowed after '?' in the block context.
+ this.allowSimpleKey = this.flowLevel == 0;
+
+ // Reset possible simple key on the current level.
+ removePossibleSimpleKey();
+
+ // Add KEY.
+ Mark startMark = reader.getMark();
+ reader.forward();
+ Mark endMark = reader.getMark();
+ Token token = new KeyToken(startMark, endMark);
+ this.tokens.add(token);
+ }
+
+ private void fetchValue() {
+ // Do we determine a simple key?
+ if (this.possibleSimpleKeys.keySet().contains(this.flowLevel)) {
+ // Add KEY.
+ SimpleKey key = this.possibleSimpleKeys.get(this.flowLevel);
+ this.possibleSimpleKeys.remove(this.flowLevel);
+ this.tokens.add(key.getTokenNumber() - this.tokensTaken, new KeyToken(key.getMark(),
+ key.getMark()));
+
+ // If this key starts a new block mapping, we need to add
+ // BLOCK-MAPPING-START.
+ if (this.flowLevel == 0) {
+ if (addIndent(key.getColumn())) {
+ this.tokens.add(key.getTokenNumber() - this.tokensTaken,
+ new BlockMappingStartToken(key.getMark(), key.getMark()));
+ }
+ }
+ // There cannot be two simple keys one after another.
+ this.allowSimpleKey = false;
+
+ } else {// It must be a part of a complex key.
+ // Block context needs additional checks.Do we really need them?
+ // They
+ // will be catched by the parser anyway.)
+ if (this.flowLevel == 0) {
+
+ // We are allowed to start a complex value if and only if we can
+ // start a simple key.
+ if (!this.allowSimpleKey) {
+ throw new ScannerException(null, null, "mapping values are not allowed here",
+ reader.getMark());
+ }
+ }
+
+ // If this value starts a new block mapping, we need to add
+ // BLOCK-MAPPING-START. It will be detected as an error later by
+ // the parser.
+ if (flowLevel == 0) {
+ if (addIndent(reader.getColumn())) {
+ Mark mark = reader.getMark();
+ this.tokens.add(new BlockMappingStartToken(mark, mark));
+ }
+ }
+
+ // Simple keys are allowed after ':' in the block context.
+ allowSimpleKey = (flowLevel == 0);
+
+ // Reset possible simple key on the current level.
+ removePossibleSimpleKey();
+ }
+ // Add VALUE.
+ Mark startMark = reader.getMark();
+ reader.forward();
+ Mark endMark = reader.getMark();
+ Token token = new ValueToken(startMark, endMark);
+ this.tokens.add(token);
+ }
+
+ private void fetchAlias() {
+ // ALIAS could be a simple key.
+ savePossibleSimpleKey();
+
+ // No simple keys after ALIAS.
+ this.allowSimpleKey = false;
+
+ // Scan and add ALIAS.
+ Token tok = scanAnchor(false);
+ this.tokens.add(tok);
+ }
+
+ private void fetchAnchor() {
+ // ANCHOR could start a simple key.
+ savePossibleSimpleKey();
+
+ // No simple keys after ANCHOR.
+ this.allowSimpleKey = false;
+
+ // Scan and add ANCHOR.
+ Token tok = scanAnchor(true);
+ this.tokens.add(tok);
+ }
+
+ private void fetchTag() {
+ // TAG could start a simple key.
+ savePossibleSimpleKey();
+
+ // No simple keys after TAG.
+ this.allowSimpleKey = false;
+
+ // Scan and add TAG.
+ Token tok = scanTag();
+ this.tokens.add(tok);
+ }
+
+ private void fetchLiteral() {
+ fetchBlockScalar('|');
+ }
+
+ private void fetchFolded() {
+ fetchBlockScalar('>');
+ }
+
+ private void fetchBlockScalar(char style) {
+ // A simple key may follow a block scalar.
+ this.allowSimpleKey = true;
+
+ // Reset possible simple key on the current level.
+ removePossibleSimpleKey();
+
+ // Scan and add SCALAR.
+ Token tok = scanBlockScalar(style);
+ this.tokens.add(tok);
+ }
+
+ private void fetchSingle() {
+ fetchFlowScalar('\'');
+ }
+
+ private void fetchDouble() {
+ fetchFlowScalar('"');
+ }
+
+ private void fetchFlowScalar(char style) {
+ // A flow scalar could be a simple key.
+ savePossibleSimpleKey();
+
+ // No simple keys after flow scalars.
+ this.allowSimpleKey = false;
+
+ // Scan and add SCALAR.
+ Token tok = scanFlowScalar(style);
+ this.tokens.add(tok);
+ }
+
+ private void fetchPlain() {
+ // A plain scalar could be a simple key.
+ savePossibleSimpleKey();
+
+ // No simple keys after plain scalars. But note that `scan_plain` will
+ // change this flag if the scan is finished at the beginning of the
+ // line.
+ this.allowSimpleKey = false;
+
+ // Scan and add SCALAR. May change `allow_simple_key`.
+ Token tok = scanPlain();
+ this.tokens.add(tok);
+ }
+
+ // Checkers.
+
+ private boolean checkDirective() {
+ // DIRECTIVE: ^ '%' ...
+ // The '%' indicator is already checked.
+ if (reader.getColumn() == 0) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ private static final String SPACES = "\0 \t\r\n\u0085\u2028\u2029";
+
+ private boolean checkDocumentStart() {
+ // DOCUMENT-START: ^ '---' (' '|'\n')
+ if (reader.getColumn() == 0) {
+ if ("---".equals(reader.prefix(3)) && SPACES.indexOf(reader.peek(3)) != -1) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean checkDocumentEnd() {
+ // DOCUMENT-END: ^ '...' (' '|'\n')
+ if (reader.getColumn() == 0) {
+ if ("...".equals(reader.prefix(3)) && SPACES.indexOf(reader.peek(3)) != -1) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean checkBlockEntry() {
+ // BLOCK-ENTRY: '-' (' '|'\n')
+ return SPACES.indexOf(reader.peek(1)) != -1;
+ }
+
+ private boolean checkKey() {
+ // KEY(flow context): '?'
+ if (this.flowLevel != 0) {
+ return true;
+ } else {
+ // KEY(block context): '?' (' '|'\n')
+ return SPACES.indexOf(reader.peek(1)) != -1;
+ }
+ }
+
+ private boolean checkValue() {
+ // VALUE(flow context): ':'
+ if (flowLevel != 0) {
+ return true;
+ } else {
+ // VALUE(block context): ':' (' '|'\n')
+ return (SPACES.indexOf(reader.peek(1)) != -1);
+ }
+ }
+
+ private boolean checkPlain() {
+ /**
+ * <pre>
+ * A plain scalar may start with any non-space character except:
+ * '-', '?', ':', ',', '[', ']', '{', '}',
+ * '#', '&amp;', '*', '!', '|', '&gt;', '\'', '\&quot;',
+ * '%', '@', '`'.
+ *
+ * It may also start with
+ * '-', '?', ':'
+ * if it is followed by a non-space character.
+ *
+ * Note that we limit the last rule to the block context (except the
+ * '-' character) because we want the flow context to be space
+ * independent.
+ * </pre>
+ */
+ char ch = reader.peek();
+ return ("\0 \t\r\n\u0085\u2028\u2029-?:,[]{}#&*!|>\'\"%@`".indexOf(ch) == -1 || ("\0 \t\r\n\u0085\u2028\u2029"
+ .indexOf(reader.peek(1)) == -1 && (ch == '-' || (this.flowLevel == 0 && "?:"
+ .indexOf(ch) != -1))));
+ }
+
+ // Scanners.
+
+ /**
+ * <pre>
+ * We ignore spaces, line breaks and comments.
+ * If we find a line break in the block context, we set the flag
+ * `allow_simple_key` on.
+ * The byte order mark is stripped if it's the first character in the
+ * stream. We do not yet support BOM inside the stream as the
+ * specification requires. Any such mark will be considered as a part
+ * of the document.
+ * TODO: We need to make tab handling rules more sane. A good rule is
+ * Tabs cannot precede tokens
+ * BLOCK-SEQUENCE-START, BLOCK-MAPPING-START, BLOCK-END,
+ * KEY(block), VALUE(block), BLOCK-ENTRY
+ * So the checking code is
+ * if &lt;TAB&gt;:
+ * self.allow_simple_keys = False
+ * We also need to add the check for `allow_simple_keys == True` to
+ * `unwind_indent` before issuing BLOCK-END.
+ * Scanners for block, flow, and plain scalars need to be modified.
+ * </pre>
+ */
+ private void scanToNextToken() {
+ if (reader.getIndex() == 0 && reader.peek() == '\uFEFF') {
+ reader.forward();
+ }
+ boolean found = false;
+ while (!found) {
+ while (reader.peek() == ' ') {
+ reader.forward();
+ }
+ if (reader.peek() == '#') {
+ while ("\0\r\n\u0085\u2028\u2029".indexOf(reader.peek()) == -1) {
+ reader.forward();
+ }
+ }
+ if (scanLineBreak().length() != 0) {
+ if (this.flowLevel == 0) {
+ this.allowSimpleKey = true;
+ }
+ } else {
+ found = true;
+ }
+ }
+ }
+
+ private Token scanDirective() {
+ // See the specification for details.
+ Mark startMark = reader.getMark();
+ Mark endMark;
+ reader.forward();
+ String name = scanDirectiveName(startMark);
+ List<?> value = null;
+ if (name.equals("YAML")) {
+ value = scanYamlDirectiveValue(startMark);
+ endMark = reader.getMark();
+ } else if (name.equals("TAG")) {
+ value = scanTagDirectiveValue(startMark);
+ endMark = reader.getMark();
+ } else {
+ endMark = reader.getMark();
+ while ("\0\r\n\u0085\u2028\u2029".indexOf(reader.peek()) == -1) {
+ reader.forward();
+ }
+ }
+ scanDirectiveIgnoredLine(startMark);
+ return new DirectiveToken(name, value, startMark, endMark);
+ }
+
+ private String scanDirectiveName(Mark startMark) {
+ // See the specification for details.
+ int length = 0;
+ char ch = reader.peek(length);
+ while (ALPHA.indexOf(ch) != -1) {
+ length++;
+ ch = reader.peek(length);
+ }
+ if (length == 0) {
+ throw new ScannerException("while scanning a directive", startMark,
+ "expected alphabetic or numeric character, but found " + ch + "(" + ((int) ch)
+ + ")", reader.getMark());
+ }
+ String value = reader.prefix(length);
+ reader.forward(length);
+ ch = reader.peek();
+ if (NULL_BL_LINEBR.indexOf(ch) == -1) {
+ throw new ScannerException("while scanning a directive", startMark,
+ "expected alphabetic or numeric character, but found " + ch + "(" + ((int) ch)
+ + ")", reader.getMark());
+ }
+ return value;
+ }
+
+ private List<Integer> scanYamlDirectiveValue(Mark startMark) {
+ // See the specification for details.
+ while (reader.peek() == ' ') {
+ reader.forward();
+ }
+ Integer major = scanYamlDirectiveNumber(startMark);
+ if (reader.peek() != '.') {
+ throw new ScannerException("while scanning a directive", startMark,
+ "expected a digit or '.', but found " + reader.peek() + "("
+ + ((int) reader.peek()) + ")", reader.getMark());
+ }
+ reader.forward();
+ Integer minor = scanYamlDirectiveNumber(startMark);
+ if (NULL_BL_LINEBR.indexOf(reader.peek()) == -1) {
+ throw new ScannerException("while scanning a directive", startMark,
+ "expected a digit or ' ', but found " + reader.peek() + "("
+ + ((int) reader.peek()) + ")", reader.getMark());
+ }
+ List<Integer> result = new ArrayList<Integer>(2);
+ result.add(major);
+ result.add(minor);
+ return result;
+ }
+
+ private Integer scanYamlDirectiveNumber(Mark startMark) {
+ // See the specification for details.
+ char ch = reader.peek();
+ if (!Character.isDigit(ch)) {
+ throw new ScannerException("while scanning a directive", startMark,
+ "expected a digit, but found " + ch + "(" + ((int) ch) + ")", reader.getMark());
+ }
+ int length = 0;
+ while (Character.isDigit(reader.peek(length))) {
+ length++;
+ }
+ Integer value = new Integer(reader.prefix(length));
+ reader.forward(length);
+ return value;
+ }
+
+ private List<String> scanTagDirectiveValue(Mark startMark) {
+ // See the specification for details.
+ while (reader.peek() == ' ') {
+ reader.forward();
+ }
+ String handle = scanTagDirectiveHandle(startMark);
+ while (reader.peek() == ' ') {
+ reader.forward();
+ }
+ String prefix = scanTagDirectivePrefix(startMark);
+ List<String> result = new ArrayList<String>(2);
+ result.add(handle);
+ result.add(prefix);
+ return result;
+ }
+
+ private String scanTagDirectiveHandle(Mark startMark) {
+ // See the specification for details.
+ String value = scanTagHandle("directive", startMark);
+ char ch = reader.peek();
+ if (ch != ' ') {
+ throw new ScannerException("while scanning a directive", startMark,
+ "expected ' ', but found " + reader.peek() + "(" + ch + ")", reader.getMark());
+ }
+ return value;
+ }
+
+ private String scanTagDirectivePrefix(Mark startMark) {
+ // See the specification for details.
+ String value = scanTagUri("directive", startMark);
+ if (NULL_BL_LINEBR.indexOf(reader.peek()) == -1) {
+ throw new ScannerException("while scanning a directive", startMark,
+ "expected ' ', but found " + reader.peek() + "(" + ((int) reader.peek()) + ")",
+ reader.getMark());
+ }
+ return value;
+ }
+
+ private String scanDirectiveIgnoredLine(Mark startMark) {
+ // See the specification for details.
+ while (reader.peek() == ' ') {
+ reader.forward();
+ }
+ if (reader.peek() == '#') {
+ while (NULL_OR_LINEBR.indexOf(reader.peek()) == -1) {
+ reader.forward();
+ }
+ }
+ char ch = reader.peek();
+ if (NULL_OR_LINEBR.indexOf(ch) == -1) {
+ throw new ScannerException("while scanning a directive", startMark,
+ "expected a comment or a line break, but found " + ch + "(" + ((int) ch) + ")",
+ reader.getMark());
+ }
+ return scanLineBreak();
+ }
+
+ /**
+ * <pre>
+ * The specification does not restrict characters for anchors and
+ * aliases. This may lead to problems, for instance, the document:
+ * [ *alias, value ]
+ * can be interpteted in two ways, as
+ * [ &quot;value&quot; ]
+ * and
+ * [ *alias , &quot;value&quot; ]
+ * Therefore we restrict aliases to numbers and ASCII letters.
+ * </pre>
+ */
+ private Token scanAnchor(boolean isAnchor) {
+ Mark startMark = reader.getMark();
+ char indicator = reader.peek();
+ String name = indicator == '*' ? "alias" : "anchor";
+ reader.forward();
+ int length = 0;
+ char ch = reader.peek(length);
+ while (ALPHA.indexOf(ch) != -1) {
+ length++;
+ ch = reader.peek(length);
+ }
+ if (length == 0) {
+ throw new ScannerException("while scanning an " + name, startMark,
+ "expected alphabetic or numeric character, but found but found " + ch, reader
+ .getMark());
+ }
+ String value = reader.prefix(length);
+ reader.forward(length);
+ ch = reader.peek();
+ if ("\0 \t\r\n\u0085\u2028\u2029?:,]}%@`".indexOf(ch) == -1) {
+ throw new ScannerException("while scanning an " + name, startMark,
+ "expected alphabetic or numeric character, but found " + ch + "("
+ + ((int) reader.peek()) + ")", reader.getMark());
+ }
+ Mark endMark = reader.getMark();
+ Token tok;
+ if (isAnchor) {
+ tok = new AnchorToken(value, startMark, endMark);
+ } else {
+ tok = new AliasToken(value, startMark, endMark);
+ }
+ return tok;
+ }
+
+ private Token scanTag() {
+ // See the specification for details.
+ Mark startMark = reader.getMark();
+ char ch = reader.peek(1);
+ String handle = null;
+ String suffix = null;
+ if (ch == '<') {
+ reader.forward(2);
+ suffix = scanTagUri("tag", startMark);
+ if (reader.peek() != '>') {
+ throw new ScannerException("while scanning a tag", startMark,
+ "expected '>', but found " + reader.peek() + "(" + ((int) reader.peek())
+ + ")", reader.getMark());
+ }
+ reader.forward();
+ } else if (NULL_BL_T_LINEBR.indexOf(ch) != -1) {
+ suffix = "!";
+ reader.forward();
+ } else {
+ int length = 1;
+ boolean useHandle = false;
+ while ("\0 \r\n\u0085\u2028\u2029".indexOf(ch) == -1) {
+ if (ch == '!') {
+ useHandle = true;
+ break;
+ }
+ length++;
+ ch = reader.peek(length);
+ }
+ handle = "!";
+ if (useHandle) {
+ handle = scanTagHandle("tag", startMark);
+ } else {
+ handle = "!";
+ reader.forward();
+ }
+ suffix = scanTagUri("tag", startMark);
+ }
+ ch = reader.peek();
+ if (NULL_BL_LINEBR.indexOf(ch) == -1) {
+ throw new ScannerException("while scanning a tag", startMark,
+ "expected ' ', but found " + ch + "(" + ((int) ch) + ")", reader.getMark());
+ }
+ String[] value = new String[] { handle, suffix };
+ Mark endMark = reader.getMark();
+ return new TagToken(value, startMark, endMark);
+ }
+
+ private Token scanBlockScalar(char style) {
+ // See the specification for details.
+ boolean folded;
+ if (style == '>') {
+ folded = true;
+ } else {
+ folded = false;
+ }
+ StringBuffer chunks = new StringBuffer();
+ Mark startMark = reader.getMark();
+ // Scan the header.
+ reader.forward();
+ Object[] chompi = scanBlockScalarIndicators(startMark);
+ Boolean chomping = (Boolean) chompi[0];
+ int increment = ((Integer) chompi[1]).intValue();
+ scanBlockScalarIgnoredLine(startMark);
+
+ // Determine the indentation level and go to the first non-empty line.
+ int minIndent = this.indent + 1;
+ if (minIndent < 1) {
+ minIndent = 1;
+ }
+ String breaks = null;
+ int maxIndent = 0;
+ int indent = 0;
+ Mark endMark;
+ if (increment == -1) {
+ Object[] brme = scanBlockScalarIndentation();
+ breaks = (String) brme[0];
+ maxIndent = ((Integer) brme[1]).intValue();
+ endMark = (Mark) brme[2];
+ indent = Math.max(minIndent, maxIndent);
+ } else {
+ indent = minIndent + increment - 1;
+ Object[] brme = scanBlockScalarBreaks(indent);
+ breaks = (String) brme[0];
+ endMark = (Mark) brme[1];
+ }
+
+ String lineBreak = "";
+
+ // Scan the inner part of the block scalar.
+ while (this.reader.getColumn() == indent && reader.peek() != '\0') {
+ chunks.append(breaks);
+ boolean leadingNonSpace = " \t".indexOf(reader.peek()) == -1;
+ int length = 0;
+ while (NULL_OR_LINEBR.indexOf(reader.peek(length)) == -1) {
+ length++;
+ }
+ chunks.append(reader.prefix(length));
+ reader.forward(length);
+ lineBreak = scanLineBreak();
+ Object[] brme = scanBlockScalarBreaks(indent);
+ breaks = (String) brme[0];
+ endMark = (Mark) brme[1];
+ if (this.reader.getColumn() == indent && reader.peek() != '\0') {
+
+ // Unfortunately, folding rules are ambiguous.
+ //
+ // This is the folding according to the specification:
+ if (folded && lineBreak.equals("\n") && leadingNonSpace
+ && " \t".indexOf(reader.peek()) == -1) {
+ if (breaks.length() == 0) {
+ chunks.append(" ");
+ }
+ } else {
+ chunks.append(lineBreak);
+ }
+ // Clark Evans's interpretation (also in the spec examples) not
+ // imported from PyYAML
+ } else {
+ break;
+ }
+ }
+ // Chomp the tail.
+ if (chomping == null || chomping.booleanValue()) {
+ chunks.append(lineBreak);
+ }
+ if (chomping != null && chomping.booleanValue()) {
+ chunks.append(breaks);
+ }
+ // We are done.
+ return new ScalarToken(chunks.toString(), false, startMark, endMark, style);
+ }
+
+ private Object[] scanBlockScalarIndicators(Mark startMark) {
+ // See the specification for details.
+ Boolean chomping = null;
+ int increment = -1;
+ char ch = reader.peek();
+ if (ch == '-' || ch == '+') {
+ if (ch == '+') {
+ chomping = Boolean.TRUE;
+ } else {
+ chomping = Boolean.FALSE;
+ }
+ reader.forward();
+ ch = reader.peek();
+ if (Character.isDigit(ch)) {
+ increment = Integer.parseInt(String.valueOf(ch));
+ if (increment == 0) {
+ throw new ScannerException("while scanning a block scalar", startMark,
+ "expected indentation indicator in the range 1-9, but found 0", reader
+ .getMark());
+ }
+ reader.forward();
+ }
+ } else if (Character.isDigit(ch)) {
+ increment = Integer.parseInt(String.valueOf(ch));
+ if (increment == 0) {
+ throw new ScannerException("while scanning a block scalar", startMark,
+ "expected indentation indicator in the range 1-9, but found 0", reader
+ .getMark());
+ }
+ reader.forward();
+ ch = reader.peek();
+ if (ch == '-' || ch == '+') {
+ if (ch == '+') {
+ chomping = Boolean.TRUE;
+ } else {
+ chomping = Boolean.FALSE;
+ }
+ reader.forward();
+ }
+ }
+ ch = reader.peek();
+ if (NULL_BL_LINEBR.indexOf(ch) == -1) {
+ throw new ScannerException("while scanning a block scalar", startMark,
+ "expected chomping or indentation indicators, but found " + ch, reader
+ .getMark());
+ }
+ return new Object[] { chomping, new Integer(increment) };
+ }
+
+ private String scanBlockScalarIgnoredLine(Mark startMark) {
+ // See the specification for details.
+ while (reader.peek() == ' ') {
+ reader.forward();
+ }
+ if (reader.peek() == '#') {
+ while (NULL_OR_LINEBR.indexOf(reader.peek()) == -1) {
+ reader.forward();
+ }
+ }
+ char ch = reader.peek();
+ if (NULL_OR_LINEBR.indexOf(ch) == -1) {
+ throw new ScannerException("while scanning a block scalar", startMark,
+ "expected a comment or a line break, but found " + ch, reader.getMark());
+ }
+ return scanLineBreak();
+ }
+
+ private Object[] scanBlockScalarIndentation() {
+ // See the specification for details.
+ StringBuffer chunks = new StringBuffer();
+ int maxIndent = 0;
+ Mark endMark = reader.getMark();
+ while (" \r\n\u0085\u2028\u2029".indexOf(reader.peek()) != -1) {
+ if (reader.peek() != ' ') {
+ chunks.append(scanLineBreak());
+ endMark = reader.getMark();
+ } else {
+ reader.forward();
+ if (this.reader.getColumn() > maxIndent) {
+ maxIndent = reader.getColumn();
+ }
+ }
+ }
+ return new Object[] { chunks.toString(), new Integer(maxIndent), endMark };
+ }
+
+ private Object[] scanBlockScalarBreaks(int indent) {
+ // See the specification for details.
+ StringBuffer chunks = new StringBuffer();
+ Mark endMark = reader.getMark();
+ while (this.reader.getColumn() < indent && reader.peek() == ' ') {
+ reader.forward();
+ }
+ while (FULL_LINEBR.indexOf(reader.peek()) != -1) {
+ chunks.append(scanLineBreak());
+ endMark = reader.getMark();
+ while (this.reader.getColumn() < indent && reader.peek() == ' ') {
+ reader.forward();
+ }
+ }
+ return new Object[] { chunks.toString(), endMark };
+ }
+
+ /**
+ * <pre>
+ * See the specification for details.
+ * Note that we loose indentation rules for quoted scalars. Quoted
+ * scalars don't need to adhere indentation because &quot; and ' clearly
+ * mark the beginning and the end of them. Therefore we are less
+ * restrictive then the specification requires. We only need to check
+ * that document separators are not included in scalars.
+ * </pre>
+ */
+ private Token scanFlowScalar(char style) {
+ boolean _double;
+ if (style == '"') {
+ _double = true;
+ } else {
+ _double = false;
+ }
+ StringBuffer chunks = new StringBuffer();
+ Mark startMark = reader.getMark();
+ char quote = reader.peek();
+ reader.forward();
+ chunks.append(scanFlowScalarNonSpaces(_double, startMark));
+ while (reader.peek() != quote) {
+ chunks.append(scanFlowScalarSpaces(startMark));
+ chunks.append(scanFlowScalarNonSpaces(_double, startMark));
+ }
+ reader.forward();
+ Mark endMark = reader.getMark();
+ return new ScalarToken(chunks.toString(), false, startMark, endMark, style);
+ }
+
+ private String scanFlowScalarNonSpaces(boolean _double, Mark startMark) {
+ // See the specification for details.
+ StringBuffer chunks = new StringBuffer();
+ while (true) {
+ int length = 0;
+ while ("\'\"\\\0 \t\r\n\u0085\u2028\u2029".indexOf(reader.peek(length)) == -1) {
+ length++;
+ }
+ if (length != 0) {
+ chunks.append(reader.prefix(length));
+ reader.forward(length);
+ }
+ char ch = reader.peek();
+ if (!_double && ch == '\'' && reader.peek(1) == '\'') {
+ chunks.append("'");
+ reader.forward(2);
+ } else if ((_double && ch == '\'') || (!_double && "\"\\".indexOf(ch) != -1)) {
+ chunks.append(ch);
+ reader.forward();
+ } else if (_double && ch == '\\') {
+ reader.forward();
+ ch = reader.peek();
+ if (ESCAPE_REPLACEMENTS.containsKey(new Character(ch))) {
+ chunks.append(ESCAPE_REPLACEMENTS.get(new Character(ch)));
+ reader.forward();
+ } else if (ESCAPE_CODES.containsKey(new Character(ch))) {
+ length = ((Integer) ESCAPE_CODES.get(new Character(ch))).intValue();
+ reader.forward();
+ String val = reader.prefix(length);
+ if (NOT_HEXA.matcher(val).find()) {
+ throw new ScannerException("while scanning a double-quoted scalar",
+ startMark, "expected escape sequence of " + length
+ + " hexadecimal numbers, but found: " + val, reader
+ .getMark());
+ }
+ char unicode = (char) Integer.parseInt(val, 16);
+ chunks.append(unicode);
+ reader.forward(length);
+ } else if (FULL_LINEBR.indexOf(ch) != -1) {
+ scanLineBreak();
+ chunks.append(scanFlowScalarBreaks(startMark));
+ } else {
+ throw new ScannerException("while scanning a double-quoted scalar", startMark,
+ "found unknown escape character " + ch + "(" + ((int) ch) + ")", reader
+ .getMark());
+ }
+ } else {
+ return chunks.toString();
+ }
+ }
+ }
+
+ private String scanFlowScalarSpaces(Mark startMark) {
+ // See the specification for details.
+ StringBuffer chunks = new StringBuffer();
+ int length = 0;
+ while (" \t".indexOf(reader.peek(length)) != -1) {
+ length++;
+ }
+ String whitespaces = reader.prefix(length);
+ reader.forward(length);
+ char ch = reader.peek();
+ if (ch == '\0') {
+ throw new ScannerException("while scanning a quoted scalar", startMark,
+ "found unexpected end of stream", reader.getMark());
+ } else if (FULL_LINEBR.indexOf(ch) != -1) {
+ String lineBreak = scanLineBreak();
+ String breaks = scanFlowScalarBreaks(startMark);
+ if (!lineBreak.equals("\n")) {
+ chunks.append(lineBreak);
+ } else if (breaks.length() == 0) {
+ chunks.append(" ");
+ }
+ chunks.append(breaks);
+ } else {
+ chunks.append(whitespaces);
+ }
+ return chunks.toString();
+ }
+
+ private String scanFlowScalarBreaks(Mark startMark) {
+ // See the specification for details.
+ StringBuffer chunks = new StringBuffer();
+ while (true) {
+ // Instead of checking indentation, we check for document
+ // separators.
+ String prefix = reader.prefix(3);
+ if ((prefix.equals("---") || prefix.equals("..."))
+ && NULL_BL_T_LINEBR.indexOf(reader.peek(3)) != -1) {
+ throw new ScannerException("while scanning a quoted scalar", startMark,
+ "found unexpected document separator", reader.getMark());
+ }
+ while (" \t".indexOf(reader.peek()) != -1) {
+ reader.forward();
+ }
+ if (FULL_LINEBR.indexOf(reader.peek()) != -1) {
+ chunks.append(scanLineBreak());
+ } else {
+ return chunks.toString();
+ }
+ }
+ }
+
+ /**
+ * <pre>
+ * See the specification for details.
+ * We add an additional restriction for the flow context:
+ * plain scalars in the flow context cannot contain ',', ':' and '?'.
+ * We also keep track of the `allow_simple_key` flag here.
+ * Indentation rules are loosed for the flow context.
+ * </pre>
+ */
+ private Token scanPlain() {
+ StringBuffer chunks = new StringBuffer();
+ Mark startMark = reader.getMark();
+ Mark endMark = startMark;
+ int indent = this.indent + 1;
+ String spaces = "";
+ while (true) {
+ char ch;
+ int length = 0;
+ if (reader.peek() == '#') {
+ break;
+ }
+ while (true) {
+ ch = reader.peek(length);
+ if ("\0 \t\r\n\u0085\u2028\u2029".indexOf(ch) != -1
+ || (this.flowLevel == 0 && ch == ':' && "\0 \t\r\n\u0085\u2028\u2029"
+ .indexOf(reader.peek(length + 1)) != -1)
+ || (this.flowLevel != 0 && ",:?[]{}".indexOf(ch) != -1)) {
+ break;
+ }
+ length++;
+ }
+ // It's not clear what we should do with ':' in the flow context.
+ if (this.flowLevel != 0 && ch == ':'
+ && "\0 \t\r\n\u0085\u2028\u2029,[]{}".indexOf(reader.peek(length + 1)) == -1) {
+ reader.forward(length);
+ throw new ScannerException("while scanning a plain scalar", startMark,
+ "found unexpected ':'", reader.getMark(),
+ "Please check http://pyyaml.org/wiki/YAMLColonInFlowContext for details.");
+ }
+ if (length == 0) {
+ break;
+ }
+ this.allowSimpleKey = false;
+ chunks.append(spaces);
+ chunks.append(reader.prefix(length));
+ reader.forward(length);
+ endMark = reader.getMark();
+ spaces = scanPlainSpaces();
+ if ("".equals(spaces) || reader.peek() == '#'
+ || (this.flowLevel == 0 && this.reader.getColumn() < indent)) {
+ break;
+ }
+ }
+ return new ScalarToken(chunks.toString(), startMark, endMark, true);
+ }
+
+ /**
+ * <pre>
+ * See the specification for details.
+ * The specification is really confusing about tabs in plain scalars.
+ * We just forbid them completely. Do not use tabs in YAML!
+ * </pre>
+ */
+ private String scanPlainSpaces() {
+ StringBuffer chunks = new StringBuffer();
+ int length = 0;
+ while (reader.peek(length) == ' ') {
+ length++;
+ }
+ String whitespaces = reader.prefix(length);
+ reader.forward(length);
+ char ch = reader.peek();
+ if (FULL_LINEBR.indexOf(ch) != -1) {
+ String lineBreak = scanLineBreak();
+ this.allowSimpleKey = true;
+ String prefix = reader.prefix(3);
+ if ("---".equals(prefix) || "...".equals(prefix)
+ && NULL_BL_T_LINEBR.indexOf(reader.peek(3)) != -1) {
+ return "";
+ }
+ StringBuffer breaks = new StringBuffer();
+ while (" \r\n\u0085\u2028\u2029".indexOf(reader.peek()) != -1) {
+ if (reader.peek() == ' ') {
+ reader.forward();
+ } else {
+ breaks.append(scanLineBreak());
+ prefix = reader.prefix(3);
+ if ("---".equals(prefix) || "...".equals(prefix)
+ && NULL_BL_T_LINEBR.indexOf(reader.peek(3)) != -1) {
+ return "";
+ }
+ }
+ }
+ if (!lineBreak.equals("\n")) {
+ chunks.append(lineBreak);
+ } else if (breaks == null || breaks.toString().equals("")) {
+ chunks.append(" ");
+ }
+ chunks.append(breaks);
+ } else {
+ chunks.append(whitespaces);
+ }
+ return chunks.toString();
+ }
+
+ /**
+ * <pre>
+ * See the specification for details.
+ * For some strange reasons, the specification does not allow '_' in
+ * tag handles. I have allowed it anyway.
+ * </pre>
+ */
+ private String scanTagHandle(String name, Mark startMark) {
+ char ch = reader.peek();
+ if (ch != '!') {
+ throw new ScannerException("while scanning a " + name, startMark,
+ "expected '!', but found " + ch + "(" + ((int) ch) + ")", reader.getMark());
+ }
+ int length = 1;
+ ch = reader.peek(length);
+ if (ch != ' ') {
+ while (ALPHA.indexOf(ch) != -1) {
+ length++;
+ ch = reader.peek(length);
+ }
+ if (ch != '!') {
+ reader.forward(length);
+ throw new ScannerException("while scanning a " + name, startMark,
+ "expected '!', but found " + ch + "(" + ((int) ch) + ")", reader.getMark());
+ }
+ length++;
+ }
+ String value = reader.prefix(length);
+ reader.forward(length);
+ return value;
+ }
+
+ private String scanTagUri(String name, Mark startMark) {
+ // See the specification for details.
+ // Note: we do not check if URI is well-formed.
+ StringBuffer chunks = new StringBuffer();
+ int length = 0;
+ char ch = reader.peek(length);
+ while (ALPHA.indexOf(ch) != -1 || "-;/?:@&=+$,_.!~*\'()[]%".indexOf(ch) != -1) {
+ if (ch == '%') {
+ chunks.append(reader.prefix(length));
+ reader.forward(length);
+ length = 0;
+ chunks.append(scanUriEscapes(name, startMark));
+ } else {
+ length++;
+ }
+ ch = reader.peek(length);
+ }
+ if (length != 0) {
+ chunks.append(reader.prefix(length));
+ reader.forward(length);
+ length = 0;
+ }
+ if (chunks.length() == 0) {
+ throw new ScannerException("while scanning a " + name, startMark,
+ "expected URI, but found " + ch + "(" + ((int) ch) + ")", reader.getMark());
+ }
+ return chunks.toString();
+ }
+
+ private String scanUriEscapes(String name, Mark startMark) {
+ // See the specification for details.
+ StringBuffer bytes = new StringBuffer();
+ while (reader.peek() == '%') {
+ reader.forward();
+ try {
+ bytes.append(Integer.parseInt(reader.prefix(2), 16));
+ } catch (NumberFormatException nfe) {
+ throw new ScannerException("while scanning a " + name, startMark,
+ "expected URI escape sequence of 2 hexadecimal numbers, but found "
+ + reader.peek(1) + "(" + ((int) reader.peek(1)) + ") and "
+ + reader.peek(2) + "(" + ((int) reader.peek(2)) + ")", reader
+ .getMark());
+ }
+ reader.forward(2);
+ }
+ return bytes.toString();
+ }
+
+ private String scanLineBreak() {
+ // Transforms:
+ // '\r\n' : '\n'
+ // '\r' : '\n'
+ // '\n' : '\n'
+ // '\x85' : '\n'
+ // default : ''
+ char ch = reader.peek();
+ if ("\r\n\u0085".indexOf(ch) != -1) {
+ if ("\r\n".equals(reader.prefix(2))) {
+ reader.forward(2);
+ } else {
+ reader.forward();
+ }
+ return "\n";
+ } else if ("\u2028\u2029".indexOf(ch) != -1) {
+ reader.forward();
+ return String.valueOf(ch);
+ }
+ return "";
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/scanner/SimpleKey.java b/src/main/java/org/yaml/snakeyaml/scanner/SimpleKey.java
new file mode 100644
index 00000000..9d49e679
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/scanner/SimpleKey.java
@@ -0,0 +1,59 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.scanner;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * Simple keys treatment.
+ *
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+final class SimpleKey {
+ private int tokenNumber;
+ private boolean required;
+ private int index;
+ private int line;
+ private int column;
+ private Mark mark;
+
+ public SimpleKey(int tokenNumber, boolean required, int index, int line, int column, Mark mark) {
+ this.tokenNumber = tokenNumber;
+ this.required = required;
+ this.index = index;
+ this.line = line;
+ this.column = column;
+ this.mark = mark;
+ }
+
+ public int getTokenNumber() {
+ return this.tokenNumber;
+ }
+
+ public int getColumn() {
+ return this.column;
+ }
+
+ public Mark getMark() {
+ return mark;
+ }
+
+ public int getIndex() {
+ return index;
+ }
+
+ public int getLine() {
+ return line;
+ }
+
+ public boolean isRequired() {
+ return required;
+ }
+
+ @Override
+ public String toString() {
+ return "SimpleKey - tokenNumber=" + tokenNumber + " required=" + required + " index="
+ + index + " line=" + line + " column=" + column;
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/serializer/Serializer.java b/src/main/java/org/yaml/snakeyaml/serializer/Serializer.java
new file mode 100644
index 00000000..0468d007
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/serializer/Serializer.java
@@ -0,0 +1,191 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.serializer;
+
+import java.io.IOException;
+import java.text.NumberFormat;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.emitter.Emitter;
+import org.yaml.snakeyaml.events.AliasEvent;
+import org.yaml.snakeyaml.events.DocumentEndEvent;
+import org.yaml.snakeyaml.events.DocumentStartEvent;
+import org.yaml.snakeyaml.events.MappingEndEvent;
+import org.yaml.snakeyaml.events.MappingStartEvent;
+import org.yaml.snakeyaml.events.ScalarEvent;
+import org.yaml.snakeyaml.events.SequenceEndEvent;
+import org.yaml.snakeyaml.events.SequenceStartEvent;
+import org.yaml.snakeyaml.events.StreamEndEvent;
+import org.yaml.snakeyaml.events.StreamStartEvent;
+import org.yaml.snakeyaml.nodes.CollectionNode;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.NodeId;
+import org.yaml.snakeyaml.nodes.ScalarNode;
+import org.yaml.snakeyaml.resolver.Resolver;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public final class Serializer {
+ private final Emitter emitter;
+ private final Resolver resolver;
+ private boolean explicitStart;
+ private boolean explicitEnd;
+ private Integer[] useVersion;
+ private Map<String, String> useTags;
+ private Set<Node> serializedNodes;
+ private Map<Node, String> anchors;
+ private int lastAnchorId;
+ private Boolean closed;
+ private String explicitRoot;
+
+ public Serializer(Emitter emitter, Resolver resolver, DumperOptions opts) {
+ this.emitter = emitter;
+ this.resolver = resolver;
+ this.explicitStart = opts.isExplicitStart();
+ this.explicitEnd = opts.isExplicitEnd();
+ if (opts.getVersion() != null) {
+ this.useVersion = opts.getVersion().getArray();
+ }
+ this.useTags = opts.getTags();
+ this.serializedNodes = new HashSet<Node>();
+ this.anchors = new HashMap<Node, String>();
+ this.lastAnchorId = 0;
+ this.closed = null;
+ this.explicitRoot = opts.getExplicitRoot();
+ }
+
+ public void open() throws IOException {
+ if (closed == null) {
+ this.emitter.emit(new StreamStartEvent(null, null));
+ this.closed = Boolean.FALSE;
+ } else if (Boolean.TRUE.equals(closed)) {
+ throw new SerializerException("serializer is closed");
+ } else {
+ throw new SerializerException("serializer is already opened");
+ }
+ }
+
+ public void close() throws IOException {
+ if (closed == null) {
+ throw new SerializerException("serializer is not opened");
+ } else if (!Boolean.TRUE.equals(closed)) {
+ this.emitter.emit(new StreamEndEvent(null, null));
+ this.closed = Boolean.TRUE;
+ }
+ }
+
+ public void serialize(Node node) throws IOException {
+ if (closed == null) {
+ throw new SerializerException("serializer is not opened");
+ } else if (closed) {
+ throw new SerializerException("serializer is closed");
+ }
+ this.emitter.emit(new DocumentStartEvent(null, null, this.explicitStart, this.useVersion,
+ useTags));
+ anchorNode(node);
+ if (explicitRoot != null) {
+ node.setTag(explicitRoot);
+ }
+ serializeNode(node, null, null);
+ this.emitter.emit(new DocumentEndEvent(null, null, this.explicitEnd));
+ this.serializedNodes.clear();
+ this.anchors.clear();
+ this.lastAnchorId = 0;
+ }
+
+ @SuppressWarnings("unchecked")
+ private void anchorNode(Node node) {
+ if (this.anchors.containsKey(node)) {
+ String anchor = this.anchors.get(node);
+ if (null == anchor) {
+ anchor = generateAnchor();
+ this.anchors.put(node, anchor);
+ }
+ } else {
+ this.anchors.put(node, null);
+ switch (node.getNodeId()) {
+ case sequence:
+ List<Node> list = (List<Node>) node.getValue();
+ for (Node item : list) {
+ anchorNode(item);
+ }
+ break;
+ case mapping:
+ List<Object[]> map = (List<Object[]>) node.getValue();
+ for (Object[] object : map) {
+ Node key = (Node) object[0];
+ Node value = (Node) object[1];
+ anchorNode(key);
+ anchorNode(value);
+ }
+ break;
+ }
+ }
+ }
+
+ private String generateAnchor() {
+ this.lastAnchorId++;
+ NumberFormat format = NumberFormat.getNumberInstance();
+ format.setMinimumIntegerDigits(3);
+ String anchorId = format.format(this.lastAnchorId);
+ return "id" + anchorId;
+ }
+
+ @SuppressWarnings("unchecked")
+ private void serializeNode(Node node, Node parent, Object index) throws IOException {
+ String tAlias = this.anchors.get(node);
+ if (this.serializedNodes.contains(node)) {
+ this.emitter.emit(new AliasEvent(tAlias, null, null));
+ } else {
+ this.serializedNodes.add(node);
+ // this.resolver.descendResolver(parent, index);
+ switch (node.getNodeId()) {
+ case scalar:
+ String detectedTag = this.resolver.resolve(NodeId.scalar, (String) node.getValue(),
+ true);
+ String defaultTag = this.resolver.resolve(NodeId.scalar, (String) node.getValue(),
+ false);
+ boolean[] implicit = new boolean[] { false, false };
+ implicit[0] = node.getTag().equals(detectedTag);
+ implicit[1] = node.getTag().equals(defaultTag);
+ ScalarEvent event = new ScalarEvent(tAlias, node.getTag(), implicit, (String) node
+ .getValue(), null, null, ((ScalarNode) node).getStyle());
+ this.emitter.emit(event);
+ break;
+ case sequence:
+ boolean implicitS = (node.getTag().equals(this.resolver.resolve(NodeId.sequence,
+ null, true)));
+ this.emitter.emit(new SequenceStartEvent(tAlias, node.getTag(), implicitS, null,
+ null, ((CollectionNode) node).getFlowStyle()));
+ int indexCounter = 0;
+ List<Node> list = (List<Node>) node.getValue();
+ for (Node item : list) {
+ serializeNode(item, node, new Integer(indexCounter));
+ indexCounter++;
+ }
+ this.emitter.emit(new SequenceEndEvent(null, null));
+ break;
+ default:// instance of MappingNode
+ String implicitTag = this.resolver.resolve(NodeId.mapping, null, true);
+ boolean implicitM = (node.getTag().equals(implicitTag));
+ this.emitter.emit(new MappingStartEvent(tAlias, node.getTag(), implicitM, null,
+ null, ((CollectionNode) node).getFlowStyle()));
+ List<Object[]> map = (List<Object[]>) node.getValue();
+ for (Object[] row : map) {
+ Node key = (Node) row[0];
+ Node value = (Node) row[1];
+ serializeNode(key, node, null);
+ serializeNode(value, node, key);
+ }
+ this.emitter.emit(new MappingEndEvent(null, null));
+ }
+ }
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/serializer/SerializerException.java b/src/main/java/org/yaml/snakeyaml/serializer/SerializerException.java
new file mode 100644
index 00000000..202abcf4
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/serializer/SerializerException.java
@@ -0,0 +1,17 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.serializer;
+
+import org.yaml.snakeyaml.error.YAMLException;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public class SerializerException extends YAMLException {
+ private static final long serialVersionUID = 2632638197498912433L;
+
+ public SerializerException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/tokens/AliasToken.java b/src/main/java/org/yaml/snakeyaml/tokens/AliasToken.java
new file mode 100644
index 00000000..aa0eba8b
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/tokens/AliasToken.java
@@ -0,0 +1,32 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public final class AliasToken extends Token {
+ private final String value;
+
+ public AliasToken(String value, Mark startMark, Mark endMark) {
+ super(startMark, endMark);
+ this.value = value;
+ }
+
+ public String getValue() {
+ return this.value;
+ }
+
+ @Override
+ protected String getArguments() {
+ return "value=" + value;
+ }
+
+ @Override
+ public String getTokenId() {
+ return "<alias>";
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/tokens/AnchorToken.java b/src/main/java/org/yaml/snakeyaml/tokens/AnchorToken.java
new file mode 100644
index 00000000..c58a967c
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/tokens/AnchorToken.java
@@ -0,0 +1,32 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public final class AnchorToken extends Token {
+ private final String value;
+
+ public AnchorToken(String value, Mark startMark, Mark endMark) {
+ super(startMark, endMark);
+ this.value = value;
+ }
+
+ public String getValue() {
+ return this.value;
+ }
+
+ @Override
+ protected String getArguments() {
+ return "value=" + value;
+ }
+
+ @Override
+ public String getTokenId() {
+ return "<anchor>";
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/tokens/BlockEndToken.java b/src/main/java/org/yaml/snakeyaml/tokens/BlockEndToken.java
new file mode 100644
index 00000000..8dbe15fc
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/tokens/BlockEndToken.java
@@ -0,0 +1,21 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public final class BlockEndToken extends Token {
+
+ public BlockEndToken(Mark startMark, Mark endMark) {
+ super(startMark, endMark);
+ }
+
+ @Override
+ public String getTokenId() {
+ return "<block end>";
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/tokens/BlockEntryToken.java b/src/main/java/org/yaml/snakeyaml/tokens/BlockEntryToken.java
new file mode 100644
index 00000000..d0ba8f0d
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/tokens/BlockEntryToken.java
@@ -0,0 +1,21 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public final class BlockEntryToken extends Token {
+
+ public BlockEntryToken(Mark startMark, Mark endMark) {
+ super(startMark, endMark);
+ }
+
+ @Override
+ public String getTokenId() {
+ return "-";
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/tokens/BlockMappingStartToken.java b/src/main/java/org/yaml/snakeyaml/tokens/BlockMappingStartToken.java
new file mode 100644
index 00000000..04616a0c
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/tokens/BlockMappingStartToken.java
@@ -0,0 +1,21 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public final class BlockMappingStartToken extends Token {
+
+ public BlockMappingStartToken(Mark startMark, Mark endMark) {
+ super(startMark, endMark);
+ }
+
+ @Override
+ public String getTokenId() {
+ return "<block mapping start>";
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/tokens/BlockSequenceStartToken.java b/src/main/java/org/yaml/snakeyaml/tokens/BlockSequenceStartToken.java
new file mode 100644
index 00000000..5df7080a
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/tokens/BlockSequenceStartToken.java
@@ -0,0 +1,21 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public final class BlockSequenceStartToken extends Token {
+
+ public BlockSequenceStartToken(Mark startMark, Mark endMark) {
+ super(startMark, endMark);
+ }
+
+ @Override
+ public String getTokenId() {
+ return "<block sequence start>";
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/tokens/DirectiveToken.java b/src/main/java/org/yaml/snakeyaml/tokens/DirectiveToken.java
new file mode 100644
index 00000000..f016ed95
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/tokens/DirectiveToken.java
@@ -0,0 +1,49 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import java.util.List;
+
+import org.yaml.snakeyaml.error.Mark;
+import org.yaml.snakeyaml.error.YAMLException;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public final class DirectiveToken extends Token {
+ private final String name;
+ private final List<?> value;
+
+ public DirectiveToken(String name, List<?> value, Mark startMark, Mark endMark) {
+ super(startMark, endMark);
+ this.name = name;
+ if (value != null && value.size() != 2) {
+ throw new YAMLException("Two strings must be provided instead of "
+ + String.valueOf(value.size()));
+ }
+ this.value = value;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ public List<?> getValue() {
+ return this.value;
+ }
+
+ @Override
+ protected String getArguments() {
+ if (value != null) {
+ return "name=" + name + ", value=[" + value.get(0) + ", " + value.get(1) + "]";
+ } else {
+ return "name=" + name;
+ }
+ }
+
+ @Override
+ public String getTokenId() {
+ return "<directive>";
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/tokens/DocumentEndToken.java b/src/main/java/org/yaml/snakeyaml/tokens/DocumentEndToken.java
new file mode 100644
index 00000000..c74b9ced
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/tokens/DocumentEndToken.java
@@ -0,0 +1,21 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public final class DocumentEndToken extends Token {
+
+ public DocumentEndToken(Mark startMark, Mark endMark) {
+ super(startMark, endMark);
+ }
+
+ @Override
+ public String getTokenId() {
+ return "<document end>";
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/tokens/DocumentStartToken.java b/src/main/java/org/yaml/snakeyaml/tokens/DocumentStartToken.java
new file mode 100644
index 00000000..845ac769
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/tokens/DocumentStartToken.java
@@ -0,0 +1,21 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public final class DocumentStartToken extends Token {
+
+ public DocumentStartToken(Mark startMark, Mark endMark) {
+ super(startMark, endMark);
+ }
+
+ @Override
+ public String getTokenId() {
+ return "<document start>";
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/tokens/FlowEntryToken.java b/src/main/java/org/yaml/snakeyaml/tokens/FlowEntryToken.java
new file mode 100644
index 00000000..620708cb
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/tokens/FlowEntryToken.java
@@ -0,0 +1,21 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public final class FlowEntryToken extends Token {
+
+ public FlowEntryToken(Mark startMark, Mark endMark) {
+ super(startMark, endMark);
+ }
+
+ @Override
+ public String getTokenId() {
+ return ",";
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/tokens/FlowMappingEndToken.java b/src/main/java/org/yaml/snakeyaml/tokens/FlowMappingEndToken.java
new file mode 100644
index 00000000..2da86fe6
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/tokens/FlowMappingEndToken.java
@@ -0,0 +1,21 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public final class FlowMappingEndToken extends Token {
+
+ public FlowMappingEndToken(Mark startMark, Mark endMark) {
+ super(startMark, endMark);
+ }
+
+ @Override
+ public String getTokenId() {
+ return "}";
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/tokens/FlowMappingStartToken.java b/src/main/java/org/yaml/snakeyaml/tokens/FlowMappingStartToken.java
new file mode 100644
index 00000000..fc553108
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/tokens/FlowMappingStartToken.java
@@ -0,0 +1,21 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public final class FlowMappingStartToken extends Token {
+
+ public FlowMappingStartToken(Mark startMark, Mark endMark) {
+ super(startMark, endMark);
+ }
+
+ @Override
+ public String getTokenId() {
+ return "{";
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/tokens/FlowSequenceEndToken.java b/src/main/java/org/yaml/snakeyaml/tokens/FlowSequenceEndToken.java
new file mode 100644
index 00000000..438eed81
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/tokens/FlowSequenceEndToken.java
@@ -0,0 +1,21 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public final class FlowSequenceEndToken extends Token {
+
+ public FlowSequenceEndToken(Mark startMark, Mark endMark) {
+ super(startMark, endMark);
+ }
+
+ @Override
+ public String getTokenId() {
+ return "]";
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/tokens/FlowSequenceStartToken.java b/src/main/java/org/yaml/snakeyaml/tokens/FlowSequenceStartToken.java
new file mode 100644
index 00000000..136e408d
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/tokens/FlowSequenceStartToken.java
@@ -0,0 +1,21 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public final class FlowSequenceStartToken extends Token {
+
+ public FlowSequenceStartToken(Mark startMark, Mark endMark) {
+ super(startMark, endMark);
+ }
+
+ @Override
+ public String getTokenId() {
+ return "[";
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/tokens/KeyToken.java b/src/main/java/org/yaml/snakeyaml/tokens/KeyToken.java
new file mode 100644
index 00000000..8d80512c
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/tokens/KeyToken.java
@@ -0,0 +1,21 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public final class KeyToken extends Token {
+
+ public KeyToken(Mark startMark, Mark endMark) {
+ super(startMark, endMark);
+ }
+
+ @Override
+ public String getTokenId() {
+ return "?";
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/tokens/ScalarToken.java b/src/main/java/org/yaml/snakeyaml/tokens/ScalarToken.java
new file mode 100644
index 00000000..90a3cbbc
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/tokens/ScalarToken.java
@@ -0,0 +1,48 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public final class ScalarToken extends Token {
+ private final String value;
+ private final boolean plain;
+ private final char style;
+
+ public ScalarToken(String value, Mark startMark, Mark endMark, boolean plain) {
+ this(value, plain, startMark, endMark, (char) 0);
+ }
+
+ public ScalarToken(String value, boolean plain, Mark startMark, Mark endMark, char style) {
+ super(startMark, endMark);
+ this.value = value;
+ this.plain = plain;
+ this.style = style;
+ }
+
+ public boolean getPlain() {
+ return this.plain;
+ }
+
+ public String getValue() {
+ return this.value;
+ }
+
+ public char getStyle() {
+ return this.style;
+ }
+
+ @Override
+ protected String getArguments() {
+ return "value=" + value + ", plain=" + plain + ", style=" + style;
+ }
+
+ @Override
+ public String getTokenId() {
+ return "<scalar>";
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/tokens/StreamEndToken.java b/src/main/java/org/yaml/snakeyaml/tokens/StreamEndToken.java
new file mode 100644
index 00000000..b14fd50a
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/tokens/StreamEndToken.java
@@ -0,0 +1,21 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public final class StreamEndToken extends Token {
+
+ public StreamEndToken(Mark startMark, Mark endMark) {
+ super(startMark, endMark);
+ }
+
+ @Override
+ public String getTokenId() {
+ return "<stream end>";
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/tokens/StreamStartToken.java b/src/main/java/org/yaml/snakeyaml/tokens/StreamStartToken.java
new file mode 100644
index 00000000..a6f26f7b
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/tokens/StreamStartToken.java
@@ -0,0 +1,21 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public final class StreamStartToken extends Token {
+
+ public StreamStartToken(Mark startMark, Mark endMark) {
+ super(startMark, endMark);
+ }
+
+ @Override
+ public String getTokenId() {
+ return "<stream start>";
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/tokens/TagToken.java b/src/main/java/org/yaml/snakeyaml/tokens/TagToken.java
new file mode 100644
index 00000000..e56bc342
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/tokens/TagToken.java
@@ -0,0 +1,37 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import org.yaml.snakeyaml.error.Mark;
+import org.yaml.snakeyaml.error.YAMLException;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public final class TagToken extends Token {
+ private final String[] value;
+
+ public TagToken(String[] value, Mark startMark, Mark endMark) {
+ super(startMark, endMark);
+ if (value.length != 2) {
+ throw new YAMLException("Two strings must be provided instead of "
+ + String.valueOf(value.length));
+ }
+ this.value = value;
+ }
+
+ public String[] getValue() {
+ return this.value;
+ }
+
+ @Override
+ protected String getArguments() {
+ return "value=[" + value[0] + ", " + value[1] + "]";
+ }
+
+ @Override
+ public String getTokenId() {
+ return "<tag>";
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/tokens/Token.java b/src/main/java/org/yaml/snakeyaml/tokens/Token.java
new file mode 100644
index 00000000..0daadd2f
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/tokens/Token.java
@@ -0,0 +1,59 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public abstract class Token {
+ private final Mark startMark;
+ private final Mark endMark;
+
+ public Token(Mark startMark, Mark endMark) {
+ assert startMark != null;
+ assert endMark != null;
+ this.startMark = startMark;
+ this.endMark = endMark;
+ }
+
+ public String toString() {
+ return "<" + this.getClass().getName() + "(" + getArguments() + ")>";
+ }
+
+ public Mark getStartMark() {
+ return startMark;
+ }
+
+ public Mark getEndMark() {
+ return endMark;
+ }
+
+ /**
+ * @see __repr__ for Token in PyYAML
+ */
+ protected String getArguments() {
+ return "";
+ }
+
+ /**
+ * For error reporting.
+ *
+ * @see class variable 'id' in PyYAML
+ */
+ public abstract String getTokenId();
+
+ /*
+ * for tests only
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof Token) {
+ return toString().equals(obj.toString());
+ } else {
+ return false;
+ }
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/tokens/ValueToken.java b/src/main/java/org/yaml/snakeyaml/tokens/ValueToken.java
new file mode 100644
index 00000000..2042aee8
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/tokens/ValueToken.java
@@ -0,0 +1,21 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public final class ValueToken extends Token {
+
+ public ValueToken(Mark startMark, Mark endMark) {
+ super(startMark, endMark);
+ }
+
+ @Override
+ public String getTokenId() {
+ return ":";
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/util/Base64Coder.java b/src/main/java/org/yaml/snakeyaml/util/Base64Coder.java
new file mode 100644
index 00000000..539c41c5
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/util/Base64Coder.java
@@ -0,0 +1,109 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.util;
+
+import org.yaml.snakeyaml.error.YAMLException;
+
+public abstract class Base64Coder {
+ // Mapping table from 6-bit nibbles to Base64 characters.
+ private final static char[] map1 = new char[64];
+ static {
+ int i = 0;
+ for (char c = 'A'; c <= 'Z'; c++)
+ map1[i++] = c;
+ for (char c = 'a'; c <= 'z'; c++)
+ map1[i++] = c;
+ for (char c = '0'; c <= '9'; c++)
+ map1[i++] = c;
+ map1[i++] = '+';
+ map1[i++] = '/';
+ }
+
+ // Mapping table from Base64 characters to 6-bit nibbles.
+ private final static byte[] map2 = new byte[128];
+ static {
+ for (int i = 0; i < map2.length; i++)
+ map2[i] = -1;
+ for (int i = 0; i < 64; i++)
+ map2[map1[i]] = (byte) i;
+ }
+
+ /**
+ * Encodes a byte array into Base64 format. No blanks or line breaks are
+ * inserted.
+ *
+ * @param in
+ * an array containing the data bytes to be encoded.
+ * @return A character array with the Base64 encoded data.
+ */
+ public static char[] encode(byte[] in) {
+ int iLen = in.length;
+ int oDataLen = (iLen * 4 + 2) / 3; // output length without padding
+ int oLen = ((iLen + 2) / 3) * 4; // output length including padding
+ char[] out = new char[oLen];
+ int ip = 0;
+ int op = 0;
+ while (ip < iLen) {
+ int i0 = in[ip++] & 0xff;
+ int i1 = ip < iLen ? in[ip++] & 0xff : 0;
+ int i2 = ip < iLen ? in[ip++] & 0xff : 0;
+ int o0 = i0 >>> 2;
+ int o1 = ((i0 & 3) << 4) | (i1 >>> 4);
+ int o2 = ((i1 & 0xf) << 2) | (i2 >>> 6);
+ int o3 = i2 & 0x3F;
+ out[op++] = map1[o0];
+ out[op++] = map1[o1];
+ out[op] = op < oDataLen ? map1[o2] : '=';
+ op++;
+ out[op] = op < oDataLen ? map1[o3] : '=';
+ op++;
+ }
+ return out;
+ }
+
+ /**
+ * Decodes Base64 data. No blanks or line breaks are allowed within the
+ * Base64 encoded data.
+ *
+ * @param in
+ * a character array containing the Base64 encoded data.
+ * @return An array containing the decoded data bytes.
+ * @throws IllegalArgumentException
+ * if the input is not valid Base64 encoded data.
+ */
+ public static byte[] decode(char[] in) {
+ int iLen = in.length;
+ if (iLen % 4 != 0)
+ throw new YAMLException("Length of Base64 encoded input string is not a multiple of 4.");
+ while (iLen > 0 && in[iLen - 1] == '=')
+ iLen--;
+ int oLen = (iLen * 3) / 4;
+ byte[] out = new byte[oLen];
+ int ip = 0;
+ int op = 0;
+ while (ip < iLen) {
+ int i0 = in[ip++];
+ int i1 = in[ip++];
+ int i2 = ip < iLen ? in[ip++] : 'A';
+ int i3 = ip < iLen ? in[ip++] : 'A';
+ if (i0 > 127 || i1 > 127 || i2 > 127 || i3 > 127)
+ throw new YAMLException("Illegal character in Base64 encoded data.");
+ int b0 = map2[i0];
+ int b1 = map2[i1];
+ int b2 = map2[i2];
+ int b3 = map2[i3];
+ if (b0 < 0 || b1 < 0 || b2 < 0 || b3 < 0)
+ throw new YAMLException("Illegal character in Base64 encoded data.");
+ int o0 = (b0 << 2) | (b1 >>> 4);
+ int o1 = ((b1 & 0xf) << 4) | (b2 >>> 2);
+ int o2 = ((b2 & 3) << 6) | b3;
+ out[op++] = (byte) o0;
+ if (op < oLen)
+ out[op++] = (byte) o1;
+ if (op < oLen)
+ out[op++] = (byte) o2;
+ }
+ return out;
+ }
+}
diff --git a/src/test/java/examples/AnyObjectExampleTest.java b/src/test/java/examples/AnyObjectExampleTest.java
new file mode 100644
index 00000000..9a599d87
--- /dev/null
+++ b/src/test/java/examples/AnyObjectExampleTest.java
@@ -0,0 +1,50 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package examples;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+
+public class AnyObjectExampleTest extends TestCase {
+ @SuppressWarnings("unchecked")
+ public void testLoad() throws IOException {
+ String doc = Util.getLocalResource("examples/any-object-example.yaml");
+ System.out.println(doc);
+ Yaml yaml = new Yaml();
+ Map<String, Object> object = (Map<String, Object>) yaml.load(doc);
+ System.out.println(object);
+ assertEquals(6, object.size());
+ assertEquals("[null, null]", object.get("none").toString());
+ List list1 = (List) object.get("none");
+ assertEquals(2, list1.size());
+ for (Object object2 : list1) {
+ assertNull(object2);
+ }
+ //
+ assertEquals("[true, false, true, false]", object.get("bool").toString());
+ assertEquals(4, ((List) object.get("bool")).size());
+ //
+ assertEquals(new Integer(42), object.get("int"));
+ assertEquals(new Double(3.14159), object.get("float"));
+ //
+ assertEquals("[LITE, RES_ACID, SUS_DEXT]", object.get("list").toString());
+ List list2 = (List) object.get("list");
+ assertEquals(3, list2.size());
+ for (Object object2 : list2) {
+ assertEquals(object2.toString(), object2.toString().toUpperCase());
+ }
+ //
+ assertEquals("{hp=13, sp=5}", object.get("dict").toString());
+ Map<String, Integer> map = (Map<String, Integer>) object.get("dict");
+ assertEquals(2, map.keySet().size());
+ assertEquals(new Integer(13), map.get("hp"));
+ assertEquals(new Integer(5), map.get("sp"));
+ }
+}
diff --git a/src/test/java/examples/CollectionStyleTest.java b/src/test/java/examples/CollectionStyleTest.java
new file mode 100644
index 00000000..4529f993
--- /dev/null
+++ b/src/test/java/examples/CollectionStyleTest.java
@@ -0,0 +1,28 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package examples;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Yaml;
+
+public class CollectionStyleTest extends TestCase {
+ public void testNestedStyle() {
+ Yaml yaml = new Yaml();
+ String document = " a: 1\n b:\n c: 3\n d: 4\n";
+ System.out.println(document);
+ System.out.println(yaml.dump(yaml.load(document)));
+ assertEquals("a: 1\nb: {c: 3, d: 4}\n", yaml.dump(yaml.load(document)));
+ }
+
+ public void testNestedStyle2() {
+ DumperOptions options = new DumperOptions();
+ options.setDefaultFlowStyle(DumperOptions.DefaultFlowStyle.BLOCK);
+ Yaml yaml = new Yaml(options);
+ String document = " a: 1\n b:\n c: 3\n d: 4\n";
+ System.out.println(yaml.dump(yaml.load(document)));
+ assertEquals("a: 1\nb:\n c: 3\n d: 4\n", yaml.dump(yaml.load(document)));
+ }
+}
diff --git a/src/test/java/examples/CustomConstructor.java b/src/test/java/examples/CustomConstructor.java
new file mode 100644
index 00000000..a057fa27
--- /dev/null
+++ b/src/test/java/examples/CustomConstructor.java
@@ -0,0 +1,22 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package examples;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.yaml.snakeyaml.Invoice;
+import org.yaml.snakeyaml.constructor.Constructor;
+
+public class CustomConstructor extends Constructor {
+
+ public CustomConstructor() {
+ super(Invoice.class);
+ }
+
+ @Override
+ protected List<Object> createDefaultList(int initSize) {
+ return new ArrayList<Object>(initSize);
+ }
+} \ No newline at end of file
diff --git a/src/test/java/examples/CustomListExampleTest.java b/src/test/java/examples/CustomListExampleTest.java
new file mode 100644
index 00000000..dc4fae51
--- /dev/null
+++ b/src/test/java/examples/CustomListExampleTest.java
@@ -0,0 +1,31 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package examples;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Loader;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.Constructor;
+
+public class CustomListExampleTest extends TestCase {
+ @SuppressWarnings("unchecked")
+ public void testList() throws IOException {
+ Loader loader = new Loader(new CustomConstructor());
+ Yaml yaml = new Yaml(loader);
+ List<Integer> data = (List<Integer>) yaml.load("[1, 2, 3]");
+ assertTrue(data instanceof ArrayList);
+ }
+
+ class CustomConstructor extends Constructor {
+ @Override
+ protected List<Object> createDefaultList(int initSize) {
+ return new ArrayList<Object>(initSize);
+ }
+ }
+}
diff --git a/src/test/java/examples/CustomMapExampleTest.java b/src/test/java/examples/CustomMapExampleTest.java
new file mode 100644
index 00000000..624cdfab
--- /dev/null
+++ b/src/test/java/examples/CustomMapExampleTest.java
@@ -0,0 +1,36 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package examples;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.TreeMap;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Loader;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.Constructor;
+
+public class CustomMapExampleTest extends TestCase {
+ @SuppressWarnings("unchecked")
+ public void testMap() throws IOException {
+ Loader loader = new Loader(new CustomConstructor());
+ Yaml yaml = new Yaml(loader);
+ Map data = (Map) yaml.load("{2: '222', 1: '111', 3: '333'}");
+ assertTrue(data instanceof TreeMap);
+ Object[] keys = data.keySet().toArray();
+ // must be sorted
+ assertEquals(new Integer(1), keys[0]);
+ assertEquals(new Integer(2), keys[1]);
+ assertEquals(new Integer(3), keys[2]);
+ }
+
+ class CustomConstructor extends Constructor {
+ @Override
+ protected Map<Object, Object> createDefaultMap() {
+ return new TreeMap<Object, Object>();
+ }
+ }
+}
diff --git a/src/test/java/examples/Dice.java b/src/test/java/examples/Dice.java
new file mode 100644
index 00000000..25a24768
--- /dev/null
+++ b/src/test/java/examples/Dice.java
@@ -0,0 +1,41 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package examples;
+
+public class Dice {
+ private Integer a;
+ private Integer b;
+
+ public Dice(Integer a, Integer b) {
+ super();
+ this.a = a;
+ this.b = b;
+ }
+
+ public Integer getA() {
+ return a;
+ }
+
+ public Integer getB() {
+ return b;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof Dice) {
+ return toString().equals(obj.toString());
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return toString().hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return "Dice " + a + "d" + b;
+ }
+}
diff --git a/src/test/java/examples/DiceExampleTest.java b/src/test/java/examples/DiceExampleTest.java
new file mode 100644
index 00000000..f0ff3728
--- /dev/null
+++ b/src/test/java/examples/DiceExampleTest.java
@@ -0,0 +1,97 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package examples;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Dumper;
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Loader;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.Construct;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.ScalarNode;
+import org.yaml.snakeyaml.representer.Represent;
+import org.yaml.snakeyaml.representer.Representer;
+
+public class DiceExampleTest extends TestCase {
+ public void testRepresenter() throws IOException {
+ Dice dice = new Dice(3, 6);
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(dice);
+ System.out.println(output);
+ assertEquals("!!examples.Dice {a: 3, b: 6}\n", output);
+ }
+
+ public void testDiceRepresenter() throws IOException {
+ Dice dice = new Dice(3, 6);
+ Map<String, Dice> data = new HashMap<String, Dice>();
+ data.put("gold", dice);
+ Yaml yaml = new Yaml(new Dumper(new DiceRepresenter(), new DumperOptions()));
+ String output = yaml.dump(data);
+ System.out.println(output);
+ assertEquals("{gold: !dice '3d6'}\n", output);
+ }
+
+ class DiceRepresenter extends Representer {
+ public DiceRepresenter() {
+ this.representers.put(Dice.class, new RepresentDice());
+ }
+
+ private class RepresentDice implements Represent {
+ public Node representData(Object data) {
+ Dice dice = (Dice) data;
+ String value = dice.getA() + "d" + dice.getB();
+ return representScalar("!dice", value);
+ }
+ }
+ }
+
+ class DiceConstructor extends Constructor {
+ public DiceConstructor() {
+ this.yamlConstructors.put("!dice", new ConstructDice());
+ }
+
+ private class ConstructDice implements Construct {
+ public Object construct(Node node) {
+ String val = (String) constructScalar((ScalarNode) node);
+ int position = val.indexOf('d');
+ Integer a = Integer.parseInt(val.substring(0, position));
+ Integer b = Integer.parseInt(val.substring(position + 1));
+ return new Dice(a, b);
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testConstructor() throws IOException {
+ Yaml yaml = new Yaml(new Loader(new DiceConstructor()));
+ Object data = yaml.load("{initial hit points: !dice '8d4'}");
+ Map<String, Dice> map = (Map<String, Dice>) data;
+ assertEquals(new Dice(8, 4), map.get("initial hit points"));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testImplicitResolver() throws IOException {
+ Yaml yaml = new Yaml(new Loader(new DiceConstructor()), new Dumper(new DiceRepresenter(),
+ new DumperOptions()));
+ yaml.addImplicitResolver("!dice", Pattern.compile("\\d+d\\d+"), "123456789");
+ // dump
+ Map<String, Dice> treasure = (Map<String, Dice>) new HashMap<String, Dice>();
+ treasure.put("treasure", new Dice(10, 20));
+ String output = yaml.dump(treasure);
+ System.out.println(output);
+ assertEquals("{treasure: 10d20}\n", output);
+ // load
+ Object data = yaml.load("{damage: 5d10}");
+ Map<String, Dice> map = (Map<String, Dice>) data;
+ assertEquals(new Dice(5, 10), map.get("damage"));
+ }
+}
diff --git a/src/test/java/examples/DumpExampleTest.java b/src/test/java/examples/DumpExampleTest.java
new file mode 100644
index 00000000..e44ce842
--- /dev/null
+++ b/src/test/java/examples/DumpExampleTest.java
@@ -0,0 +1,128 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package examples;
+
+import java.io.StringWriter;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Yaml;
+
+public class DumpExampleTest extends TestCase {
+ public void testDump() {
+ Map<String, Object> data = new HashMap<String, Object>();
+ data.put("name", "Silenthand Olleander");
+ data.put("race", "Human");
+ data.put("traits", new String[] { "ONE_HAND", "ONE_EYE" });
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(data);
+ System.out.println(output);
+ assertTrue(output.contains("name: Silenthand Olleander"));
+ assertTrue(output.contains("race: Human"));
+ assertTrue(output.contains("traits: [ONE_HAND, ONE_EYE]"));
+ }
+
+ public void testDumpWriter() {
+ Map<String, Object> data = new HashMap<String, Object>();
+ data.put("name", "Silenthand Olleander");
+ data.put("race", "Human");
+ data.put("traits", new String[] { "ONE_HAND", "ONE_EYE" });
+ Yaml yaml = new Yaml();
+ StringWriter writer = new StringWriter();
+ yaml.dump(data, writer);
+ System.out.println(writer.toString());
+ assertTrue(writer.toString().contains("name: Silenthand Olleander"));
+ assertTrue(writer.toString().contains("race: Human"));
+ assertTrue(writer.toString().contains("traits: [ONE_HAND, ONE_EYE]"));
+ }
+
+ public void testDumpMany() {
+ List<Integer> docs = new LinkedList<Integer>();
+ for (int i = 1; i < 4; i++) {
+ docs.add(i);
+ }
+ DumperOptions options = new DumperOptions();
+ options.setExplicitStart(true);
+ Yaml yaml = new Yaml(options);
+ System.out.println(yaml.dump(docs));
+ System.out.println(yaml.dumpAll(docs.iterator()));
+ }
+
+ public void testDumpCustomJavaClass() {
+ Hero hero = new Hero("Galain Ysseleg", -3, 2);
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(hero);
+ System.out.println(output);
+ assertEquals("!!examples.Hero {hp: -3, name: Galain Ysseleg, sp: 2}\n", output);
+ }
+
+ public void testDumperOptions() {
+ List<Integer> data = new LinkedList<Integer>();
+ for (int i = 0; i < 50; i++) {
+ data.add(i);
+ }
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(data);
+ System.out.println(output);
+ assertTrue(output.contains("[0, 1, 2, 3, 4, 5, 6, 7, 8"));
+ //
+ DumperOptions options = new DumperOptions();
+ options.setWidth(50);
+ options.setIndent(4);
+ yaml = new Yaml(options);
+ output = yaml.dump(data);
+ System.out.println(output);
+ }
+
+ public void testDumperOptionsCanonical() {
+ List<Integer> data = new LinkedList<Integer>();
+ for (int i = 0; i < 5; i++) {
+ data.add(i);
+ }
+ DumperOptions options = new DumperOptions();
+ options.setCanonical(true);
+ Yaml yaml = new Yaml(options);
+ String output = yaml.dump(data);
+ System.out.println(output);
+ assertTrue(output.contains("---"));
+ assertTrue(output.contains("!!seq ["));
+ assertTrue(output.contains("!!int \"3\","));
+ }
+
+ public void testDumperOptionsFlowStyle() {
+ List<Integer> data = new LinkedList<Integer>();
+ for (int i = 0; i < 5; i++) {
+ data.add(i);
+ }
+ DumperOptions options = new DumperOptions();
+ options.setDefaultFlowStyle(DumperOptions.DefaultFlowStyle.BLOCK);
+ Yaml yaml = new Yaml(options);
+ String output = yaml.dump(data);
+ System.out.println(output);
+ assertTrue(output.contains("- 0\n"));
+ assertTrue(output.contains("- 1\n"));
+ assertTrue(output.contains("- 4\n"));
+ }
+
+ public void testDumperOptionsStyle() {
+ List<Integer> data = new LinkedList<Integer>();
+ for (int i = 0; i < 5; i++) {
+ data.add(i);
+ }
+ DumperOptions options = new DumperOptions();
+ options.setDefaultStyle(DumperOptions.DefaultScalarStyle.DOUBLE_QUOTED);
+ Yaml yaml = new Yaml(options);
+ String output = yaml.dump(data);
+ System.out.println(output);
+ assertTrue(output.contains("- !!int \"0\""));
+ assertTrue(output.contains("- !!int \"1\""));
+ assertTrue(output.contains("- !!int \"4\""));
+ }
+
+}
diff --git a/src/test/java/examples/Hero.java b/src/test/java/examples/Hero.java
new file mode 100644
index 00000000..6cdf874a
--- /dev/null
+++ b/src/test/java/examples/Hero.java
@@ -0,0 +1,30 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package examples;
+
+public class Hero {
+ private String name;
+ private Integer sp;
+ private Integer hp;
+
+ public Hero(String name, Integer hp, Integer sp) {
+ super();
+ this.name = name;
+ this.sp = sp;
+ this.hp = hp;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Integer getSp() {
+ return sp;
+ }
+
+ public Integer getHp() {
+ return hp;
+ }
+
+}
diff --git a/src/test/java/examples/LoadExampleTest.java b/src/test/java/examples/LoadExampleTest.java
new file mode 100644
index 00000000..652c5d51
--- /dev/null
+++ b/src/test/java/examples/LoadExampleTest.java
@@ -0,0 +1,59 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package examples;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+
+public class LoadExampleTest extends TestCase {
+ @SuppressWarnings("unchecked")
+ public void testLoad() {
+ Yaml yaml = new Yaml();
+ String document = "\n- Hesperiidae\n- Papilionidae\n- Apatelodidae\n- Epiplemidae";
+ System.out.println(document);
+ List<String> list = (List<String>) yaml.load(document);
+ System.out.println(list);
+ assertEquals("[Hesperiidae, Papilionidae, Apatelodidae, Epiplemidae]", list.toString());
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testLoadFromString() {
+ Yaml yaml = new Yaml();
+ String document = "hello: 25";
+ Map map = (Map) yaml.load(document);
+ assertEquals("{hello=25}", map.toString());
+ assertEquals(new Integer(25), map.get("hello"));
+ }
+
+ public void testLoadFromStream() throws FileNotFoundException {
+ InputStream input = new FileInputStream(new File("src/test/resources/reader/utf-8.txt"));
+ Yaml yaml = new Yaml();
+ Object data = yaml.load(input);
+ assertEquals("test", data);
+ //
+ data = yaml.load(new ByteArrayInputStream("test2".getBytes()));
+ assertEquals("test2", data);
+ }
+
+ public void testLoadManyDocuments() throws FileNotFoundException {
+ InputStream input = new FileInputStream(new File(
+ "src/test/resources/specification/example2_28.yaml"));
+ Yaml yaml = new Yaml();
+ int counter = 0;
+ for (Object data : yaml.loadAll(input)) {
+ System.out.println(data);
+ counter++;
+ }
+ assertEquals(3, counter);
+ }
+}
diff --git a/src/test/java/examples/SafeConstructorExampleTest.java b/src/test/java/examples/SafeConstructorExampleTest.java
new file mode 100644
index 00000000..34f5a7dd
--- /dev/null
+++ b/src/test/java/examples/SafeConstructorExampleTest.java
@@ -0,0 +1,42 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package examples;
+
+import java.io.IOException;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Loader;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.SafeConstructor;
+
+public class SafeConstructorExampleTest extends TestCase {
+ @SuppressWarnings("unchecked")
+ public void testConstruct() throws IOException {
+ String doc = "- 5\n- Person\n- true";
+ Loader loader = new Loader(new SafeConstructor());
+ Yaml yaml = new Yaml(loader);
+ List<Object> list = (List<Object>) yaml.load(doc);
+ System.out.println(list);
+ assertEquals(3, list.size());
+ assertEquals(new Integer(5), list.get(0));
+ assertEquals("Person", list.get(1));
+ assertEquals(Boolean.TRUE, list.get(2));
+ }
+
+ public void testSafeConstruct() throws IOException {
+ String doc = "- 5\n- !org.yaml.snakeyaml.constructor.Person\n firstName: Andrey\n age: 99\n- true";
+ Loader loader = new Loader(new SafeConstructor());
+ Yaml yaml = new Yaml(loader);
+ try {
+ yaml.load(doc);
+ fail("Custom Java classes should not be created.");
+ } catch (Exception e) {
+ assertEquals(
+ "null; could not determine a constructor for the tag !org.yaml.snakeyaml.constructor.Person",
+ e.getMessage());
+ }
+ }
+}
diff --git a/src/test/java/examples/SpringTest.java b/src/test/java/examples/SpringTest.java
new file mode 100644
index 00000000..fdead4fd
--- /dev/null
+++ b/src/test/java/examples/SpringTest.java
@@ -0,0 +1,21 @@
+package examples;
+
+import junit.framework.TestCase;
+
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+import org.yaml.snakeyaml.Yaml;
+
+public class SpringTest extends TestCase {
+ public void testSimple() {
+ ApplicationContext context = new ClassPathXmlApplicationContext("examples/spring.xml");
+ Yaml yaml = (Yaml) context.getBean("standardYaml");
+ assertNotNull(yaml);
+ //
+ yaml = (Yaml) context.getBean("javabeanYaml");
+ assertNotNull(yaml);
+ //
+ yaml = (Yaml) context.getBean("snakeYaml");
+ assertNotNull(yaml);
+ }
+} \ No newline at end of file
diff --git a/src/test/java/org/pyyaml/AnInstance.java b/src/test/java/org/pyyaml/AnInstance.java
new file mode 100644
index 00000000..655360dc
--- /dev/null
+++ b/src/test/java/org/pyyaml/AnInstance.java
@@ -0,0 +1,34 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.pyyaml;
+
+public class AnInstance {
+ private Object foo;
+ private Object bar;
+
+ public AnInstance() {
+ }
+
+ public AnInstance(Object foo, Object bar) {
+ this.foo = foo;
+ this.bar = bar;
+ }
+
+ public Object getFoo() {
+ return foo;
+ }
+
+ public void setFoo(Object foo) {
+ this.foo = foo;
+ }
+
+ public Object getBar() {
+ return bar;
+ }
+
+ public void setBar(Object bar) {
+ this.bar = bar;
+ }
+
+} \ No newline at end of file
diff --git a/src/test/java/org/pyyaml/CanonicalException.java b/src/test/java/org/pyyaml/CanonicalException.java
new file mode 100644
index 00000000..4bec5757
--- /dev/null
+++ b/src/test/java/org/pyyaml/CanonicalException.java
@@ -0,0 +1,19 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.pyyaml;
+
+import org.yaml.snakeyaml.error.YAMLException;
+
+public class CanonicalException extends YAMLException {
+
+ private static final long serialVersionUID = -6489045150083747626L;
+
+ public CanonicalException(String message) {
+ super(message);
+ }
+
+ public CanonicalException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/src/test/java/org/pyyaml/CanonicalLoader.java b/src/test/java/org/pyyaml/CanonicalLoader.java
new file mode 100644
index 00000000..6d54306c
--- /dev/null
+++ b/src/test/java/org/pyyaml/CanonicalLoader.java
@@ -0,0 +1,72 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.pyyaml;
+
+import java.io.IOException;
+import java.util.Iterator;
+
+import org.yaml.snakeyaml.Loader;
+import org.yaml.snakeyaml.composer.Composer;
+import org.yaml.snakeyaml.error.YAMLException;
+
+public class CanonicalLoader extends Loader {
+ @Override
+ public Object load(java.io.Reader yaml) {
+ try {
+ int ch = yaml.read();
+ StringBuffer buffer = new StringBuffer();
+ while (ch != -1) {
+ buffer.append((char) ch);
+ ch = yaml.read();
+ }
+ Composer composer = new Composer(new CanonicalParser(buffer.toString()), resolver);
+ constructor.setComposer(composer);
+ return constructor.getSingleData();
+ } catch (IOException e) {
+ throw new YAMLException(e);
+ }
+ }
+
+ public Iterable<Object> loadAll(java.io.Reader yaml) {
+ try {
+ int ch = yaml.read();
+ StringBuffer buffer = new StringBuffer();
+ while (ch != -1) {
+ buffer.append((char) ch);
+ ch = yaml.read();
+ }
+ Composer composer = new Composer(new CanonicalParser(buffer.toString()), resolver);
+ this.constructor.setComposer(composer);
+ Iterator<Object> result = new Iterator<Object>() {
+ public boolean hasNext() {
+ return constructor.checkData();
+ }
+
+ public Object next() {
+ return constructor.getData();
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ return new YamlIterable(result);
+ } catch (IOException e) {
+ throw new YAMLException(e);
+ }
+ }
+
+ private class YamlIterable implements Iterable<Object> {
+ private Iterator<Object> iterator;
+
+ public YamlIterable(Iterator<Object> iterator) {
+ this.iterator = iterator;
+ }
+
+ public Iterator<Object> iterator() {
+ return iterator;
+ }
+
+ }
+}
diff --git a/src/test/java/org/pyyaml/CanonicalParser.java b/src/test/java/org/pyyaml/CanonicalParser.java
new file mode 100644
index 00000000..f3a302f3
--- /dev/null
+++ b/src/test/java/org/pyyaml/CanonicalParser.java
@@ -0,0 +1,198 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.pyyaml;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.yaml.snakeyaml.events.AliasEvent;
+import org.yaml.snakeyaml.events.DocumentEndEvent;
+import org.yaml.snakeyaml.events.DocumentStartEvent;
+import org.yaml.snakeyaml.events.Event;
+import org.yaml.snakeyaml.events.MappingEndEvent;
+import org.yaml.snakeyaml.events.MappingStartEvent;
+import org.yaml.snakeyaml.events.ScalarEvent;
+import org.yaml.snakeyaml.events.SequenceEndEvent;
+import org.yaml.snakeyaml.events.SequenceStartEvent;
+import org.yaml.snakeyaml.events.StreamEndEvent;
+import org.yaml.snakeyaml.events.StreamStartEvent;
+import org.yaml.snakeyaml.parser.Parser;
+import org.yaml.snakeyaml.tokens.AliasToken;
+import org.yaml.snakeyaml.tokens.AnchorToken;
+import org.yaml.snakeyaml.tokens.DirectiveToken;
+import org.yaml.snakeyaml.tokens.DocumentStartToken;
+import org.yaml.snakeyaml.tokens.FlowEntryToken;
+import org.yaml.snakeyaml.tokens.FlowMappingEndToken;
+import org.yaml.snakeyaml.tokens.FlowMappingStartToken;
+import org.yaml.snakeyaml.tokens.FlowSequenceEndToken;
+import org.yaml.snakeyaml.tokens.FlowSequenceStartToken;
+import org.yaml.snakeyaml.tokens.KeyToken;
+import org.yaml.snakeyaml.tokens.ScalarToken;
+import org.yaml.snakeyaml.tokens.StreamEndToken;
+import org.yaml.snakeyaml.tokens.StreamStartToken;
+import org.yaml.snakeyaml.tokens.TagToken;
+import org.yaml.snakeyaml.tokens.Token;
+import org.yaml.snakeyaml.tokens.ValueToken;
+
+public class CanonicalParser implements Parser {
+ private LinkedList<Event> events;
+ private boolean parsed;
+ private CanonicalScanner scanner;
+
+ public CanonicalParser(String data) {
+ events = new LinkedList<Event>();
+ parsed = false;
+ scanner = new CanonicalScanner(data);
+ }
+
+ // stream: STREAM-START document* STREAM-END
+ private void parseStream() {
+ scanner.getToken(StreamStartToken.class);
+ events.add(new StreamStartEvent(null, null));
+ while (!scanner.checkToken(StreamEndToken.class)) {
+ List<Class<? extends Token>> list = new ArrayList<Class<? extends Token>>();
+ list.add(DirectiveToken.class);
+ list.add(DocumentStartToken.class);
+ if (scanner.checkToken(list)) {
+ parseDocument();
+ } else {
+ throw new CanonicalException("document is expected, got " + scanner.tokens.get(0));
+ }
+ }
+ scanner.getToken(StreamEndToken.class);
+ events.add(new StreamEndEvent(null, null));
+ }
+
+ // document: DIRECTIVE? DOCUMENT-START node
+ private void parseDocument() {
+ if (scanner.checkToken(DirectiveToken.class)) {
+ scanner.getToken(DirectiveToken.class);
+ }
+ scanner.getToken(DocumentStartToken.class);
+ events.add(new DocumentStartEvent(null, null, true, new Integer[] { 1, 1 }, null));
+ parseNode();
+ events.add(new DocumentEndEvent(null, null, true));
+ }
+
+ // node: ALIAS | ANCHOR? TAG? (SCALAR|sequence|mapping)
+ private void parseNode() {
+ if (scanner.checkToken(AliasToken.class)) {
+ AliasToken token = (AliasToken) scanner.getToken();
+ events.add(new AliasEvent(token.getValue(), null, null));
+ } else {
+ String anchor = null;
+ if (scanner.checkToken(AnchorToken.class)) {
+ AnchorToken token = (AnchorToken) scanner.getToken();
+ anchor = token.getValue();
+ }
+ String tag = null;
+ if (scanner.checkToken(TagToken.class)) {
+ TagToken token = (TagToken) scanner.getToken();
+ tag = token.getValue()[0] + token.getValue()[1];
+ }
+ if (scanner.checkToken(ScalarToken.class)) {
+ ScalarToken token = (ScalarToken) scanner.getToken();
+ events.add(new ScalarEvent(anchor, tag, new boolean[] { false, false }, token
+ .getValue(), null, null, null));
+ } else if (scanner.checkToken(FlowSequenceStartToken.class)) {
+ events.add(new SequenceStartEvent(anchor, tag, false, null, null, null));
+ parseSequence();
+ } else if (scanner.checkToken(FlowMappingStartToken.class)) {
+ events.add(new MappingStartEvent(anchor, tag, false, null, null, null));
+ parseMapping();
+ } else {
+ throw new CanonicalException("SCALAR, '[', or '{' is expected, got "
+ + scanner.tokens.get(0));
+ }
+ }
+ }
+
+ // sequence: SEQUENCE-START (node (ENTRY node)*)? ENTRY? SEQUENCE-END
+ private void parseSequence() {
+ scanner.getToken(FlowSequenceStartToken.class);
+ if (!scanner.checkToken(FlowSequenceEndToken.class)) {
+ parseNode();
+ while (!scanner.checkToken(FlowSequenceEndToken.class)) {
+ scanner.getToken(FlowEntryToken.class);
+ if (!scanner.checkToken(FlowSequenceEndToken.class)) {
+ parseNode();
+ }
+ }
+ }
+ scanner.getToken(FlowSequenceEndToken.class);
+ events.add(new SequenceEndEvent(null, null));
+ }
+
+ // mapping: MAPPING-START (map_entry (ENTRY map_entry)*)? ENTRY? MAPPING-END
+ private void parseMapping() {
+ scanner.getToken(FlowMappingStartToken.class);
+ if (!scanner.checkToken(FlowMappingEndToken.class)) {
+ parseMapEntry();
+ while (!scanner.checkToken(FlowMappingEndToken.class)) {
+ scanner.getToken(FlowEntryToken.class);
+ if (!scanner.checkToken(FlowMappingEndToken.class)) {
+ parseMapEntry();
+ }
+ }
+ }
+ scanner.getToken(FlowMappingEndToken.class);
+ events.add(new MappingEndEvent(null, null));
+ }
+
+ // map_entry: KEY node VALUE node
+ private void parseMapEntry() {
+ scanner.getToken(KeyToken.class);
+ parseNode();
+ scanner.getToken(ValueToken.class);
+ parseNode();
+ }
+
+ public void parse() {
+ parseStream();
+ parsed = true;
+ }
+
+ public Event getEvent() {
+ if (!parsed) {
+ parse();
+ }
+ return events.removeFirst();
+ }
+
+ public boolean checkEvent(List<Class<? extends Event>> choices) {
+ if (!parsed) {
+ parse();
+ }
+ if (!events.isEmpty()) {
+ if (choices.isEmpty()) {
+ return true;
+ }
+ for (Class<? extends Event> class1 : choices) {
+ if (class1.isInstance(events.peek())) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public boolean checkEvent(Class<? extends Event> choice) {
+ List<Class<? extends Event>> list = new ArrayList<Class<? extends Event>>(1);
+ list.add(choice);
+ return checkEvent(list);
+ }
+
+ public Event peekEvent() {
+ if (!parsed) {
+ parse();
+ }
+ if (events.isEmpty()) {
+ return null;
+ } else {
+ return events.get(0);
+ }
+ }
+
+}
diff --git a/src/test/java/org/pyyaml/CanonicalScanner.java b/src/test/java/org/pyyaml/CanonicalScanner.java
new file mode 100644
index 00000000..146cdf98
--- /dev/null
+++ b/src/test/java/org/pyyaml/CanonicalScanner.java
@@ -0,0 +1,301 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.pyyaml;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.yaml.snakeyaml.error.Mark;
+import org.yaml.snakeyaml.scanner.Scanner;
+import org.yaml.snakeyaml.scanner.ScannerImpl;
+import org.yaml.snakeyaml.tokens.AliasToken;
+import org.yaml.snakeyaml.tokens.AnchorToken;
+import org.yaml.snakeyaml.tokens.DirectiveToken;
+import org.yaml.snakeyaml.tokens.DocumentStartToken;
+import org.yaml.snakeyaml.tokens.FlowEntryToken;
+import org.yaml.snakeyaml.tokens.FlowMappingEndToken;
+import org.yaml.snakeyaml.tokens.FlowMappingStartToken;
+import org.yaml.snakeyaml.tokens.FlowSequenceEndToken;
+import org.yaml.snakeyaml.tokens.FlowSequenceStartToken;
+import org.yaml.snakeyaml.tokens.KeyToken;
+import org.yaml.snakeyaml.tokens.ScalarToken;
+import org.yaml.snakeyaml.tokens.StreamEndToken;
+import org.yaml.snakeyaml.tokens.StreamStartToken;
+import org.yaml.snakeyaml.tokens.TagToken;
+import org.yaml.snakeyaml.tokens.Token;
+import org.yaml.snakeyaml.tokens.ValueToken;
+
+public class CanonicalScanner implements Scanner {
+ private static final String DIRECTIVE = "%YAML 1.1";
+ private final static Map<Character, Integer> QUOTE_CODES = ScannerImpl.ESCAPE_CODES;
+
+ private final static Map<Character, String> QUOTE_REPLACES = ScannerImpl.ESCAPE_REPLACEMENTS;
+
+ private String data;
+ private int index;
+ public LinkedList<Token> tokens;
+ private boolean scanned;
+ private Mark mark;
+
+ public CanonicalScanner(String data) {
+ this.data = data + "\0";
+ this.index = 0;
+ this.tokens = new LinkedList<Token>();
+ this.scanned = false;
+ this.mark = new Mark("test", 0, 0, 0, data, 0);
+ }
+
+ public boolean checkToken(List<Class<? extends Token>> choices) {
+ if (!scanned) {
+ scan();
+ }
+ if (!tokens.isEmpty()) {
+ if (choices.isEmpty()) {
+ return true;
+ }
+ Token first = this.tokens.get(0);
+ for (Class<? extends Token> choice : choices) {
+ if (choice.isInstance(first)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public boolean checkToken(Class<? extends Token> choice) {
+ List<Class<? extends Token>> list = new ArrayList<Class<? extends Token>>();
+ list.add(choice);
+ return checkToken(list);
+ }
+
+ public Token peekToken() {
+ if (!scanned) {
+ scan();
+ }
+ if (!tokens.isEmpty()) {
+ Token first = this.tokens.get(0);
+ return first;
+ }
+ return null;
+ }
+
+ public Token getToken() {
+ if (!scanned) {
+ scan();
+ }
+ Token token = this.tokens.poll();
+ return token;
+ }
+
+ public Token getToken(Class<? extends Token> choice) {
+ Token token = getToken();
+ if (choice != null && !choice.isInstance(token)) {
+ throw new CanonicalException("unexpected token " + token);
+ }
+ return token;
+ }
+
+ private void scan() {
+ this.tokens.add(new StreamStartToken(mark, mark));
+ boolean stop = false;
+ while (!stop) {
+ findToken();
+ char ch = data.charAt(index);
+ switch (ch) {
+ case '\0':
+ tokens.add(new StreamEndToken(mark, mark));
+ stop = true;
+ break;
+
+ case '%':
+ tokens.add(scanDirective());
+ break;
+
+ case '-':
+ if ("---".equals(data.substring(index, index + 3))) {
+ index += 3;
+ tokens.add(new DocumentStartToken(mark, mark));
+ }
+ break;
+
+ case '[':
+ index++;
+ tokens.add(new FlowSequenceStartToken(mark, mark));
+ break;
+
+ case '{':
+ index++;
+ tokens.add(new FlowMappingStartToken(mark, mark));
+ break;
+
+ case ']':
+ index++;
+ tokens.add(new FlowSequenceEndToken(mark, mark));
+ break;
+
+ case '}':
+ index++;
+ tokens.add(new FlowMappingEndToken(mark, mark));
+ break;
+
+ case '?':
+ index++;
+ tokens.add(new KeyToken(mark, mark));
+ break;
+
+ case ':':
+ index++;
+ tokens.add(new ValueToken(mark, mark));
+ break;
+
+ case ',':
+ index++;
+ tokens.add(new FlowEntryToken(mark, mark));
+ break;
+
+ case '*':
+ tokens.add(scanAlias());
+ break;
+
+ case '&':
+ tokens.add(scanAlias());
+ break;
+
+ case '!':
+ tokens.add(scanTag());
+ break;
+
+ case '"':
+ tokens.add(scanScalar());
+ break;
+
+ default:
+ throw new CanonicalException("invalid token");
+ }
+ }
+ scanned = true;
+ }
+
+ private Token scanDirective() {
+ String chunk1 = data.substring(index, index + DIRECTIVE.length());
+ char chunk2 = data.charAt(index + DIRECTIVE.length());
+ if (DIRECTIVE.equals(chunk1) && "\n\0".indexOf(chunk2) != -1) {
+ index += DIRECTIVE.length();
+ List<Integer> implicit = new ArrayList<Integer>(2);
+ implicit.add(new Integer(1));
+ implicit.add(new Integer(1));
+ return new DirectiveToken("YAML", implicit, mark, mark);
+ } else {
+ throw new CanonicalException("invalid directive");
+ }
+ }
+
+ private Token scanAlias() {
+ boolean isTokenClassAlias;
+ if (data.charAt(index) == '*') {
+ isTokenClassAlias = true;
+ } else {
+ isTokenClassAlias = false;
+ }
+ index++;
+ int start = index;
+ while (", \n\0".indexOf(data.charAt(index)) == -1) {
+ index++;
+ }
+ String value = data.substring(start, index);
+ Token token;
+ if (isTokenClassAlias) {
+ token = new AliasToken(value, mark, mark);
+ } else {
+ token = new AnchorToken(value, mark, mark);
+ }
+ return token;
+ }
+
+ private Token scanTag() {
+ index++;
+ int start = index;
+ while (" \n\0".indexOf(data.charAt(index)) == -1) {
+ index++;
+ }
+ String value = data.substring(start, index);
+ if (value.length() == 0) {
+ value = "!";
+ } else if (value.charAt(0) == '!') {
+ value = "tag:yaml.org,2002:" + value.substring(1);
+ } else if (value.charAt(0) == '<' && value.charAt(value.length() - 1) == '>') {
+ value = value.substring(1, value.length() - 1);
+ } else {
+ value = "!" + value;
+ }
+ return new TagToken(new String[] { "", value }, mark, mark);
+ }
+
+ private Token scanScalar() {
+ index++;
+ StringBuffer chunks = new StringBuffer();
+ int start = index;
+ boolean ignoreSpaces = false;
+ while (data.charAt(index) != '"') {
+ if (data.charAt(index) == '\\') {
+ ignoreSpaces = false;
+ chunks.append(data.substring(start, index));
+ index++;
+ char ch = data.charAt(index);
+ index++;
+ if (ch == '\n') {
+ ignoreSpaces = true;
+ } else if (QUOTE_CODES.keySet().contains(ch)) {
+ int length = QUOTE_CODES.get(ch);
+ int code = Integer.parseInt(data.substring(index, index + length), 16);
+ chunks.append(String.valueOf((char) code));
+ index += length;
+ } else {
+ if (!QUOTE_REPLACES.keySet().contains(ch)) {
+ throw new CanonicalException("invalid escape code");
+ }
+ chunks.append(QUOTE_REPLACES.get(ch));
+ }
+ start = index;
+ } else if (data.charAt(index) == '\n') {
+ chunks.append(data.substring(start, index));
+ chunks.append(" ");
+ index++;
+ start = index;
+ ignoreSpaces = true;
+ } else if (ignoreSpaces && data.charAt(index) == ' ') {
+ index++;
+ start = index;
+ } else {
+ ignoreSpaces = false;
+ index++;
+ }
+ }
+ chunks.append(data.substring(start, index));
+ index++;
+ return new ScalarToken(chunks.toString(), mark, mark, false);
+ }
+
+ private void findToken() {
+ boolean found = false;
+ while (!found) {
+ while (" \t".indexOf(data.charAt(index)) != -1) {
+ index++;
+ }
+ if (data.charAt(index) == '#') {
+ while (data.charAt(index) != '\n') {
+ index++;
+ }
+ }
+ if (data.charAt(index) == '\n') {
+ index++;
+ } else {
+ found = true;
+ }
+ }
+ }
+}
diff --git a/src/test/java/org/pyyaml/PyCanonicalTest.java b/src/test/java/org/pyyaml/PyCanonicalTest.java
new file mode 100644
index 00000000..41a9e8e2
--- /dev/null
+++ b/src/test/java/org/pyyaml/PyCanonicalTest.java
@@ -0,0 +1,53 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.pyyaml;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.yaml.snakeyaml.events.Event;
+import org.yaml.snakeyaml.tokens.Token;
+
+/**
+ * @see imported from PyYAML
+ */
+public class PyCanonicalTest extends PyImportTest {
+
+ public void testCanonicalScanner() throws IOException {
+ File[] files = getStreamsByExtension(".canonical");
+ assertTrue("No test files found.", files.length > 0);
+ for (int i = 0; i < files.length; i++) {
+ List<Token> tokens = canonicalScan(new FileInputStream(files[i]));
+ assertFalse(tokens.isEmpty());
+ }
+ }
+
+ private List<Token> canonicalScan(InputStream input) throws IOException {
+ int ch = input.read();
+ StringBuffer buffer = new StringBuffer();
+ while (ch != -1) {
+ buffer.append((char) ch);
+ ch = input.read();
+ }
+ CanonicalScanner scanner = new CanonicalScanner(buffer.toString());
+ List<Token> result = new LinkedList<Token>();
+ while (scanner.peekToken() != null) {
+ result.add(scanner.getToken());
+ }
+ return result;
+ }
+
+ public void testCanonicalParser() throws IOException {
+ File[] files = getStreamsByExtension(".canonical");
+ assertTrue("No test files found.", files.length > 0);
+ for (int i = 0; i < files.length; i++) {
+ List<Event> tokens = canonicalParse(new FileInputStream(files[i]));
+ assertFalse(tokens.isEmpty());
+ }
+ }
+}
diff --git a/src/test/java/org/pyyaml/PyEmitterTest.java b/src/test/java/org/pyyaml/PyEmitterTest.java
new file mode 100644
index 00000000..f2de9a65
--- /dev/null
+++ b/src/test/java/org/pyyaml/PyEmitterTest.java
@@ -0,0 +1,284 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.pyyaml;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Loader;
+import org.yaml.snakeyaml.emitter.Emitter;
+import org.yaml.snakeyaml.emitter.EventsLoader;
+import org.yaml.snakeyaml.events.CollectionStartEvent;
+import org.yaml.snakeyaml.events.Event;
+import org.yaml.snakeyaml.events.MappingStartEvent;
+import org.yaml.snakeyaml.events.NodeEvent;
+import org.yaml.snakeyaml.events.ScalarEvent;
+import org.yaml.snakeyaml.events.SequenceStartEvent;
+import org.yaml.snakeyaml.parser.Parser;
+import org.yaml.snakeyaml.parser.ParserImpl;
+import org.yaml.snakeyaml.reader.Reader;
+import org.yaml.snakeyaml.reader.UnicodeReader;
+
+/**
+ * @see imported from PyYAML
+ */
+public class PyEmitterTest extends PyImportTest {
+ public void testEmitterOnData() throws IOException {
+ _testEmitter(".data", false);
+ }
+
+ public void testEmitterOnCanonicalNormally() throws IOException {
+ _testEmitter(".canonical", false);
+ }
+
+ public void testEmitterOnCanonicalCanonically() throws IOException {
+ _testEmitter(".canonical", true);
+ }
+
+ private void _testEmitter(String mask, boolean canonical) throws IOException {
+ File[] files = getStreamsByExtension(mask, true);
+ assertTrue("No test files found.", files.length > 0);
+ for (File file : files) {
+ // if (!file.getName().contains("spec-06-01.canonical")) {
+ // continue;
+ // }
+ try {
+ List<Event> events = parse(new FileInputStream(file));
+ //
+ StringWriter stream = new StringWriter();
+ DumperOptions options = new DumperOptions();
+ options.setCanonical(canonical);
+ Emitter emitter = new Emitter(stream, options);
+ for (Event event : events) {
+ emitter.emit(event);
+ }
+ //
+ String data = stream.toString();
+ List<Event> newEvents = new LinkedList<Event>();
+ Reader reader = new Reader(data);
+ Parser parser = new ParserImpl(reader);
+ while (parser.peekEvent() != null) {
+ Event event = parser.getEvent();
+ newEvents.add(event);
+ }
+ // check
+ assertEquals(events.size(), newEvents.size());
+ Iterator<Event> iter1 = events.iterator();
+ Iterator<Event> iter2 = newEvents.iterator();
+ while (iter1.hasNext()) {
+ Event event = iter1.next();
+ Event newEvent = iter2.next();
+ assertEquals(event.getClass().getName(), newEvent.getClass().getName());
+ if (event instanceof NodeEvent) {
+ NodeEvent e1 = (NodeEvent) event;
+ NodeEvent e2 = (NodeEvent) newEvent;
+ assertEquals(e1.getAnchor(), e2.getAnchor());
+ }
+ if (event instanceof CollectionStartEvent) {
+ CollectionStartEvent e1 = (CollectionStartEvent) event;
+ CollectionStartEvent e2 = (CollectionStartEvent) newEvent;
+ assertEquals(e1.getTag(), e2.getTag());
+ }
+ if (event instanceof ScalarEvent) {
+ ScalarEvent e1 = (ScalarEvent) event;
+ ScalarEvent e2 = (ScalarEvent) newEvent;
+ boolean[] implicit1 = e1.getImplicit();
+ boolean[] implicit2 = e2.getImplicit();
+ if (!implicit1[0] && !implicit1[1] && !implicit2[0] && !implicit2[1]) {
+ assertEquals(e1.getTag(), e2.getTag());
+ }
+ assertEquals(e1.getValue(), e2.getValue());
+ }
+ }
+ } catch (Exception e) {
+ System.out.println("Failed File: " + file);
+ // fail("Failed File: " + file + "; " + e.getMessage());
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testEmitterStyles() throws IOException {
+ File[] canonicalFiles = getStreamsByExtension(".canonical", false);
+ assertTrue("No test files found.", canonicalFiles.length > 0);
+ File[] dataFiles = getStreamsByExtension(".data", true);
+ assertTrue("No test files found.", dataFiles.length > 0);
+ List<File> allFiles = new LinkedList(Arrays.asList(canonicalFiles));
+ allFiles.addAll(Arrays.asList(dataFiles));
+ for (File file : allFiles) {
+ try {
+ List<Event> events = new LinkedList<Event>();
+ Reader reader = new Reader(new UnicodeReader(new FileInputStream(file)));
+ Parser parser = new ParserImpl(reader);
+ while (parser.peekEvent() != null) {
+ Event event = parser.getEvent();
+ events.add(event);
+ }
+ //
+ for (Boolean flowStyle : new Boolean[] { Boolean.FALSE, Boolean.TRUE }) {
+ for (DumperOptions.DefaultScalarStyle style : DumperOptions.DefaultScalarStyle
+ .values()) {
+ List<Event> styledEvents = new LinkedList<Event>();
+ for (Event event : events) {
+ if (event instanceof ScalarEvent) {
+ ScalarEvent scalar = (ScalarEvent) event;
+ event = new ScalarEvent(scalar.getAnchor(), scalar.getTag(), scalar
+ .getImplicit(), scalar.getValue(), scalar.getStartMark(),
+ scalar.getEndMark(), style.getChar());
+ } else if (event instanceof SequenceStartEvent) {
+ SequenceStartEvent seqStart = (SequenceStartEvent) event;
+ event = new SequenceStartEvent(seqStart.getAnchor(), seqStart
+ .getTag(), seqStart.getImplicit(), seqStart.getStartMark(),
+ seqStart.getEndMark(), flowStyle);
+ } else if (event instanceof MappingStartEvent) {
+ MappingStartEvent mapStart = (MappingStartEvent) event;
+ event = new MappingStartEvent(mapStart.getAnchor(), mapStart
+ .getTag(), mapStart.getImplicit(), mapStart.getStartMark(),
+ mapStart.getEndMark(), flowStyle);
+ }
+ styledEvents.add(event);
+ }
+ // emit
+ String data = emit(styledEvents);
+ List<Event> newEvents = parse(data);
+ assertEquals("Events must not change. File: " + file, events.size(),
+ newEvents.size());
+ Iterator<Event> oldIter = events.iterator();
+ Iterator<Event> newIter = newEvents.iterator();
+ while (oldIter.hasNext()) {
+ Event event = oldIter.next();
+ Event newEvent = newIter.next();
+ assertEquals(event.getClass(), newEvent.getClass());
+ if (event instanceof NodeEvent) {
+ assertEquals(((NodeEvent) event).getAnchor(),
+ ((NodeEvent) newEvent).getAnchor());
+ }
+ if (event instanceof CollectionStartEvent) {
+ assertEquals(((CollectionStartEvent) event).getTag(),
+ ((CollectionStartEvent) newEvent).getTag());
+ }
+ if (event instanceof ScalarEvent) {
+ ScalarEvent scalarOld = (ScalarEvent) event;
+ ScalarEvent scalarNew = (ScalarEvent) newEvent;
+ boolean[] oldImplicit = scalarOld.getImplicit();
+ boolean[] newImplicit = scalarNew.getImplicit();
+ if (!oldImplicit[0] && !oldImplicit[1] && !newImplicit[0]
+ && !newImplicit[1]) {
+ assertEquals(scalarOld.getTag(), scalarNew.getTag());
+ }
+ assertEquals(scalarOld.getValue(), scalarNew.getValue());
+ }
+ }
+ }
+ }
+
+ } catch (Exception e) {
+ System.out.println("Failed File: " + file);
+ // fail("Failed File: " + file + "; " + e.getMessage());
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ private String emit(List<Event> events) throws IOException {
+ StringWriter writer = new StringWriter();
+ Emitter emitter = new Emitter(writer, new DumperOptions());
+ for (Event event : events) {
+ emitter.emit(event);
+ }
+ return writer.toString();
+ }
+
+ private List<Event> parse(String data) {
+ ParserImpl parser = new ParserImpl(new Reader(data));
+ List<Event> newEvents = new LinkedList<Event>();
+ while (parser.peekEvent() != null) {
+ newEvents.add(parser.getEvent());
+ }
+ return newEvents;
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testEmitterEvents() throws IOException {
+ File[] files = getStreamsByExtension(".events", false);
+ assertTrue("No test files found.", files.length > 0);
+ for (File file : files) {
+ // if (!file.getName().contains("spec-06-01.canonical")) {
+ // continue;
+ // }
+ try {
+ Loader loader = new EventsLoader();
+ List<Event> events = new LinkedList<Event>();
+ String content = getResource(file.getName());
+ events = (List<Event>) load(loader, content);
+ //
+ StringWriter stream = new StringWriter();
+ Emitter emitter = new Emitter(stream, new DumperOptions());
+ for (Event event : events) {
+ emitter.emit(event);
+ }
+ //
+ String data = stream.toString();
+ List<Event> newEvents = new LinkedList<Event>();
+ Reader reader = new Reader(data);
+ Parser parser = new ParserImpl(reader);
+ while (parser.peekEvent() != null) {
+ Event event = parser.getEvent();
+ newEvents.add(event);
+ }
+ // check
+ assertEquals(events.size(), newEvents.size());
+ Iterator<Event> iter1 = events.iterator();
+ Iterator<Event> iter2 = newEvents.iterator();
+ while (iter1.hasNext()) {
+ Event event = iter1.next();
+ Event newEvent = iter2.next();
+ assertEquals(event.getClass().getName(), newEvent.getClass().getName());
+ if (event instanceof NodeEvent) {
+ NodeEvent e1 = (NodeEvent) event;
+ NodeEvent e2 = (NodeEvent) newEvent;
+ assertEquals(e1.getAnchor(), e2.getAnchor());
+ }
+ if (event instanceof CollectionStartEvent) {
+ CollectionStartEvent e1 = (CollectionStartEvent) event;
+ CollectionStartEvent e2 = (CollectionStartEvent) newEvent;
+ assertEquals(e1.getTag(), e2.getTag());
+ }
+ if (event instanceof ScalarEvent) {
+ ScalarEvent e1 = (ScalarEvent) event;
+ ScalarEvent e2 = (ScalarEvent) newEvent;
+ boolean[] implicit1 = e1.getImplicit();
+ boolean[] implicit2 = e2.getImplicit();
+ if (implicit1[0] == implicit2[0] && implicit1[1] == implicit2[1]) {
+
+ } else {
+ if ((e1.getTag() == null || e2.getTag() == null)
+ || e1.getTag().equals(e2.getTag())) {
+
+ } else {
+ System.out.println("tag1: " + e1.getTag());
+ System.out.println("tag2: " + e2.getTag());
+ fail("in file: " + file);
+ }
+ }
+ assertEquals(e1.getValue(), e2.getValue());
+ }
+ }
+ } catch (Exception e) {
+ System.out.println("Failed File: " + file);
+ // fail("Failed File: " + file + "; " + e.getMessage());
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+}
diff --git a/src/test/java/org/pyyaml/PyErrorsTest.java b/src/test/java/org/pyyaml/PyErrorsTest.java
new file mode 100644
index 00000000..8eb46962
--- /dev/null
+++ b/src/test/java/org/pyyaml/PyErrorsTest.java
@@ -0,0 +1,120 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.pyyaml;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Loader;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.emitter.Emitter;
+import org.yaml.snakeyaml.emitter.EventConstructor;
+import org.yaml.snakeyaml.error.YAMLException;
+import org.yaml.snakeyaml.events.Event;
+
+/**
+ * @see imported from PyYAML
+ */
+public class PyErrorsTest extends PyImportTest {
+ private boolean skip(String filename) {
+ List<String> failures = new ArrayList<String>();
+ // in python list cannot be a key in a dictionary.
+ failures.add("unacceptable-key.loader-error");
+ for (String name : failures) {
+ if (name.equals(filename)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public void testLoaderErrors() throws FileNotFoundException {
+ File[] files = getStreamsByExtension(".loader-error");
+ assertTrue("No test files found.", files.length > 0);
+ for (int i = 0; i < files.length; i++) {
+ if (skip(files[i].getName())) {
+ continue;
+ }
+ try {
+ for (Object document : loadAll(new FileInputStream(files[i]))) {
+ assertNotNull("File " + files[i], document);
+ }
+ fail("Loading must fail for " + files[i].getAbsolutePath());
+ // System.err.println("Loading must fail for " +
+ // files[i].getAbsolutePath());
+ } catch (Exception e) {
+ assertTrue(true);
+ }
+ }
+ }
+
+ public void testLoaderStringErrors() throws FileNotFoundException {
+ File[] files = getStreamsByExtension(".loader-error");
+ assertTrue("No test files found.", files.length > 0);
+ for (int i = 0; i < files.length; i++) {
+ if (skip(files[i].getName())) {
+ continue;
+ }
+ try {
+ String content = getResource(files[i].getName());
+ for (Object document : loadAll(content.trim())) {
+ assertNotNull(document);
+ }
+ fail("Loading must fail for " + files[i].getAbsolutePath());
+ // System.err.println("Loading must fail for " +
+ // files[i].getAbsolutePath());
+ } catch (Exception e) {
+ assertTrue(true);
+ }
+ }
+ }
+
+ public void testLoaderSingleErrors() throws FileNotFoundException {
+ File[] files = getStreamsByExtension(".single-loader-error");
+ assertTrue("No test files found.", files.length > 0);
+ for (int i = 0; i < files.length; i++) {
+ try {
+ String content = getResource(files[i].getName());
+ load(content.trim());
+ fail("Loading must fail for " + files[i].getAbsolutePath());
+ // multiple documents must not be accepted
+ System.err.println("Loading must fail for " + files[i].getAbsolutePath());
+ } catch (YAMLException e) {
+ assertTrue(true);
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testEmitterErrors() {
+ File[] files = getStreamsByExtension(".emitter-error");
+ assertTrue("No test files found.", files.length > 0);
+ for (int i = 0; i < files.length; i++) {
+ Constructor constructor = new EventConstructor();
+ Loader loader = new Loader(constructor);
+ String content = getResource(files[i].getName());
+ List<Event> document = (List<Event>) load(loader, content.trim());
+ Writer writer = new StringWriter();
+ Emitter emitter = new Emitter(writer, new DumperOptions());
+ try {
+ for (Event event : document) {
+ emitter.emit(event);
+ }
+ fail("Loading must fail for " + files[i].getAbsolutePath());
+ // System.err.println("Loading must fail for " +
+ // files[i].getAbsolutePath());
+ } catch (Exception e) {
+ assertTrue(true);
+ }
+ }
+ }
+
+ // testDumperErrors() is implemented in SerializerTest.java
+}
diff --git a/src/test/java/org/pyyaml/PyImportTest.java b/src/test/java/org/pyyaml/PyImportTest.java
new file mode 100644
index 00000000..5bc7fe77
--- /dev/null
+++ b/src/test/java/org/pyyaml/PyImportTest.java
@@ -0,0 +1,128 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.pyyaml;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.LinkedList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Loader;
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.events.Event;
+import org.yaml.snakeyaml.parser.Parser;
+import org.yaml.snakeyaml.parser.ParserImpl;
+import org.yaml.snakeyaml.reader.Reader;
+import org.yaml.snakeyaml.reader.UnicodeReader;
+
+public abstract class PyImportTest extends TestCase {
+ public static final String PATH = "pyyaml";
+
+ protected Object load(String data) {
+ Yaml yaml = new Yaml();
+ Object obj = yaml.load(data);
+ return obj;
+ }
+
+ protected Object load(Loader loader, String data) {
+ Yaml yaml = new Yaml(loader);
+ Object obj = yaml.load(data);
+ return obj;
+ }
+
+ protected Iterable<Object> loadAll(InputStream data) {
+ Yaml yaml = new Yaml();
+ return yaml.loadAll(data);
+ }
+
+ protected Iterable<Object> loadAll(String data) {
+ Yaml yaml = new Yaml();
+ return yaml.loadAll(data);
+ }
+
+ protected Iterable<Object> loadAll(Loader loader, String data) {
+ Yaml yaml = new Yaml(loader);
+ return yaml.loadAll(data);
+ }
+
+ protected String getResource(String theName) {
+ try {
+ String content;
+ content = Util.getLocalResource(PATH + File.separator + theName);
+ return content;
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ protected File[] getStreamsByExtension(String extention) {
+ return getStreamsByExtension(extention, false);
+ }
+
+ protected File[] getStreamsByExtension(String extention, boolean onlyIfCanonicalPresent) {
+ File file = new File("src/test/resources/pyyaml");
+ assertTrue("Folder not found: " + file.getAbsolutePath(), file.exists());
+ assertTrue(file.isDirectory());
+ File[] files = file.listFiles(new PyFilenameFilter(extention, onlyIfCanonicalPresent));
+ return files;
+ }
+
+ protected File getFileByName(String name) {
+ File file = new File("src/test/resources/pyyaml/" + name);
+ assertTrue("Folder not found: " + file.getAbsolutePath(), file.exists());
+ assertTrue(file.isFile());
+ return file;
+ }
+
+ protected List<Event> canonicalParse(InputStream input2) throws IOException {
+ Reader reader = new Reader(new UnicodeReader(input2));
+ StringBuffer buffer = new StringBuffer();
+ while (reader.peek() != '\0') {
+ buffer.append(reader.peek());
+ reader.forward();
+ }
+ CanonicalParser parser = new CanonicalParser(buffer.toString());
+ List<Event> result = new LinkedList<Event>();
+ while (parser.peekEvent() != null) {
+ result.add(parser.getEvent());
+ }
+ return result;
+ }
+
+ protected List<Event> parse(InputStream input) throws IOException {
+ Reader reader = new Reader(new UnicodeReader(input));
+ Parser parser = new ParserImpl(reader);
+ List<Event> result = new LinkedList<Event>();
+ while (parser.peekEvent() != null) {
+ result.add(parser.getEvent());
+ }
+ return result;
+ }
+
+ private class PyFilenameFilter implements FilenameFilter {
+ private String extension;
+ private boolean onlyIfCanonicalPresent;
+
+ public PyFilenameFilter(String extension, boolean onlyIfCanonicalPresent) {
+ this.extension = extension;
+ this.onlyIfCanonicalPresent = onlyIfCanonicalPresent;
+ }
+
+ public boolean accept(File dir, String name) {
+ int position = name.lastIndexOf('.');
+ String canonicalFileName = name.substring(0, position) + ".canonical";
+ File canonicalFile = new File(dir, canonicalFileName);
+ if (onlyIfCanonicalPresent && !canonicalFile.exists()) {
+ return false;
+ } else {
+ return name.endsWith(extension);
+ }
+ }
+ }
+}
diff --git a/src/test/java/org/pyyaml/PyMarkTest.java b/src/test/java/org/pyyaml/PyMarkTest.java
new file mode 100644
index 00000000..fe078385
--- /dev/null
+++ b/src/test/java/org/pyyaml/PyMarkTest.java
@@ -0,0 +1,45 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.pyyaml;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * @see imported from PyYAML
+ */
+public class PyMarkTest extends PyImportTest {
+
+ public void testMarks() {
+ String content = getResource("test_mark.marks");
+ String[] inputs = content.split("---\n");
+ for (int i = 1; i < inputs.length; i++) {
+ String input = inputs[i];
+ int index = 0;
+ int line = 0;
+ int column = 0;
+ while (input.charAt(index) != '*') {
+ if (input.charAt(index) != '\n') {
+ line += 1;
+ column = 0;
+ } else {
+ column += 1;
+ }
+ index += 1;
+ }
+ Mark mark = new Mark("testMarks", index, line, column, input, index);
+ String snippet = mark.get_snippet(2, 79);
+ assertTrue("Must only have one '\n'.", snippet.indexOf("\n") > -1);
+ assertEquals("Must only have only one '\n'.", snippet.indexOf("\n"), snippet
+ .lastIndexOf("\n"));
+ String[] lines = snippet.split("\n");
+ String data = lines[0];
+ String pointer = lines[1];
+ assertTrue("Mark must be restricted: " + data, data.length() < 82);
+ int dataPosition = data.indexOf("*");
+ int pointerPosition = pointer.indexOf("^");
+ assertEquals("Pointer should coincide with '*':\n " + snippet, dataPosition,
+ pointerPosition);
+ }
+ }
+}
diff --git a/src/test/java/org/pyyaml/PyReaderTest.java b/src/test/java/org/pyyaml/PyReaderTest.java
new file mode 100644
index 00000000..c9891d76
--- /dev/null
+++ b/src/test/java/org/pyyaml/PyReaderTest.java
@@ -0,0 +1,36 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.pyyaml;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+
+import org.yaml.snakeyaml.reader.Reader;
+import org.yaml.snakeyaml.reader.ReaderException;
+import org.yaml.snakeyaml.reader.UnicodeReader;
+
+/**
+ * @see imported from PyYAML
+ */
+public class PyReaderTest extends PyImportTest {
+
+ public void testReaderUnicodeErrors() throws IOException {
+ File[] inputs = getStreamsByExtension(".stream-error");
+ for (int i = 0; i < inputs.length; i++) {
+ Reader stream = new Reader(new UnicodeReader(new FileInputStream(inputs[i])));
+ try {
+ while (stream.peek() != '\u0000') {
+ stream.forward();
+ }
+ fail("Invalid stream must not be accepted: " + inputs[i].getAbsolutePath()
+ + "; encoding=" + stream.getEncoding());
+ } catch (ReaderException e) {
+ System.out.println(e.toString());
+ assertTrue(true);
+ }
+ }
+ }
+
+}
diff --git a/src/test/java/org/pyyaml/PyRecursiveTest.java b/src/test/java/org/pyyaml/PyRecursiveTest.java
new file mode 100644
index 00000000..14fb5d51
--- /dev/null
+++ b/src/test/java/org/pyyaml/PyRecursiveTest.java
@@ -0,0 +1,63 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.pyyaml;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.ConstructorException;
+
+public class PyRecursiveTest extends TestCase {
+
+ @SuppressWarnings("unchecked")
+ public void testDict() {
+ Map<AnInstance, AnInstance> value = new HashMap<AnInstance, AnInstance>();
+ AnInstance instance = new AnInstance(value, value);
+ value.put(instance, instance);
+ Yaml yaml = new Yaml();
+ try {
+ String output1 = yaml.dump(value);
+ Map<AnInstance, AnInstance> value2 = (Map<AnInstance, AnInstance>) yaml.load(output1);
+ assertEquals(value, value2);
+ } catch (ConstructorException e) {
+ // TODO recursive objects are not allowed
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testList() {
+ List value = new ArrayList();
+ value.add(value);
+ Yaml yaml = new Yaml();
+ try {
+ String output1 = yaml.dump(value);
+ System.out.println(output1);
+ List value2 = (List) yaml.load(output1);
+ assertEquals(value, value2);
+ } catch (ConstructorException e) {
+ // TODO recursive objects are not allowed
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testSet() {
+ Set value = new HashSet();
+ value.add(new AnInstance(value, value));
+ Yaml yaml = new Yaml();
+ try {
+ String output1 = yaml.dump(value);
+ List value2 = (List) yaml.load(output1);
+ assertEquals(value, value2);
+ } catch (ConstructorException e) {
+ // TODO recursive objects are not allowed
+ }
+ }
+}
diff --git a/src/test/java/org/pyyaml/PyStructureTest.java b/src/test/java/org/pyyaml/PyStructureTest.java
new file mode 100644
index 00000000..0362ee5c
--- /dev/null
+++ b/src/test/java/org/pyyaml/PyStructureTest.java
@@ -0,0 +1,287 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.pyyaml;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.yaml.snakeyaml.Loader;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.composer.Composer;
+import org.yaml.snakeyaml.constructor.Construct;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.events.AliasEvent;
+import org.yaml.snakeyaml.events.CollectionStartEvent;
+import org.yaml.snakeyaml.events.Event;
+import org.yaml.snakeyaml.events.ScalarEvent;
+import org.yaml.snakeyaml.nodes.MappingNode;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.ScalarNode;
+import org.yaml.snakeyaml.nodes.SequenceNode;
+import org.yaml.snakeyaml.parser.ParserImpl;
+import org.yaml.snakeyaml.reader.Reader;
+import org.yaml.snakeyaml.reader.UnicodeReader;
+import org.yaml.snakeyaml.resolver.Resolver;
+
+/**
+ * @see imported from PyYAML
+ */
+public class PyStructureTest extends PyImportTest {
+
+ private void compareEvents(List<Event> events1, List<Event> events2, boolean full) {
+ assertEquals(events1.size(), events2.size());
+ Iterator<Event> iter1 = events1.iterator();
+ Iterator<Event> iter2 = events2.iterator();
+ while (iter1.hasNext()) {
+ Event event1 = iter1.next();
+ Event event2 = iter2.next();
+ assertEquals(event1.getClass(), event2.getClass());
+ if (event1 instanceof AliasEvent && full) {
+ assertEquals(((AliasEvent) event1).getAnchor(), ((AliasEvent) event2).getAnchor());
+ }
+ if (event1 instanceof CollectionStartEvent) {
+ String tag1 = ((CollectionStartEvent) event1).getTag();
+ String tag2 = ((CollectionStartEvent) event1).getTag();
+ if (tag1 != null && !"!".equals(tag1) && tag2 != null && !"!".equals(tag1)) {
+ assertEquals(tag1, tag2);
+ }
+ }
+ if (event1 instanceof ScalarEvent) {
+ ScalarEvent scalar1 = (ScalarEvent) event1;
+ ScalarEvent scalar2 = (ScalarEvent) event2;
+ boolean[] oldImplicit = scalar1.getImplicit();
+ boolean[] newImplicit = scalar2.getImplicit();
+ if (!oldImplicit[0] && !oldImplicit[1] && !newImplicit[0] && !newImplicit[1]) {
+ assertEquals(scalar1.getTag(), scalar2.getTag());
+ }
+ assertEquals(scalar1.getValue(), scalar2.getValue());
+ }
+ }
+ }
+
+ public void testParser() throws IOException {
+ File[] files = getStreamsByExtension(".data", true);
+ assertTrue("No test files found.", files.length > 0);
+ for (File file : files) {
+ if (!file.getName().contains("scan-line-b")) {
+ continue;
+ }
+ try {
+ List<Event> events1 = parse(new FileInputStream(file));
+ assertFalse(events1.isEmpty());
+ int index = file.getAbsolutePath().lastIndexOf('.');
+ String canonicalName = file.getAbsolutePath().substring(0, index) + ".canonical";
+ File canonical = new File(canonicalName);
+ List<Event> events2 = canonicalParse(new FileInputStream(canonical));
+ assertFalse(events2.isEmpty());
+ System.out.println("try:" + file);
+ compareEvents(events1, events2, false);
+ } catch (Exception e) {
+ System.out.println("Failed File: " + file);
+ // fail("Failed File: " + file + "; " + e.getMessage());
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ public void testParserOnCanonical() throws IOException {
+ File[] canonicalFiles = getStreamsByExtension(".canonical", false);
+ assertTrue("No test files found.", canonicalFiles.length > 0);
+ for (File file : canonicalFiles) {
+ try {
+ List<Event> events1 = parse(new FileInputStream(file));
+ assertFalse(events1.isEmpty());
+ List<Event> events2 = canonicalParse(new FileInputStream(file));
+ assertFalse(events2.isEmpty());
+ compareEvents(events1, events2, true);
+ } catch (Exception e) {
+ System.out.println("Failed File: " + file);
+ // fail("Failed File: " + file + "; " + e.getMessage());
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ private void compareNodes(Node node1, Node node2) {
+ assertEquals(node1.getClass(), node2.getClass());
+ if (node1 instanceof ScalarNode) {
+ ScalarNode scalar1 = (ScalarNode) node1;
+ ScalarNode scalar2 = (ScalarNode) node2;
+ assertEquals(scalar1.getTag(), scalar2.getTag());
+ assertEquals(scalar1.getValue(), scalar2.getValue());
+ } else {
+ if (node1 instanceof SequenceNode) {
+ SequenceNode seq1 = (SequenceNode) node1;
+ SequenceNode seq2 = (SequenceNode) node2;
+ assertEquals(seq1.getTag(), seq2.getTag());
+ assertEquals(seq1.getValue().size(), seq2.getValue().size());
+ Iterator<Node> iter2 = seq2.getValue().iterator();
+ for (Node child1 : seq1.getValue()) {
+ Node child2 = iter2.next();
+ compareNodes(child1, child2);
+ }
+ } else {
+ MappingNode seq1 = (MappingNode) node1;
+ MappingNode seq2 = (MappingNode) node2;
+ assertEquals(seq1.getTag(), seq2.getTag());
+ assertEquals(seq1.getValue().size(), seq2.getValue().size());
+ Iterator<Node[]> iter2 = seq2.getValue().iterator();
+ for (Node[] child1 : seq1.getValue()) {
+ Node[] child2 = iter2.next();
+ compareNodes(child1[0], child2[0]);// keys
+ compareNodes(child1[1], child2[1]);// values
+ }
+ }
+ }
+ }
+
+ public void testComposer() throws IOException {
+ File[] files = getStreamsByExtension(".data", true);
+ assertTrue("No test files found.", files.length > 0);
+ for (File file : files) {
+ try {
+ List<Node> events1 = compose_all(new FileInputStream(file));
+ int index = file.getAbsolutePath().lastIndexOf('.');
+ String canonicalName = file.getAbsolutePath().substring(0, index) + ".canonical";
+ File canonical = new File(canonicalName);
+ List<Node> events2 = canonical_compose_all(new FileInputStream(canonical));
+ assertEquals(events1.size(), events2.size());
+ Iterator<Node> iter1 = events1.iterator();
+ Iterator<Node> iter2 = events2.iterator();
+ while (iter1.hasNext()) {
+ compareNodes(iter1.next(), iter2.next());
+ }
+ } catch (Exception e) {
+ System.out.println("Failed File: " + file);
+ // fail("Failed File: " + file + "; " + e.getMessage());
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ private List<Node> compose_all(InputStream file) {
+ Composer composer = new Composer(new ParserImpl(new Reader(new UnicodeReader(file))),
+ new Resolver());
+ List<Node> documents = new LinkedList<Node>();
+ while (composer.checkNode()) {
+ documents.add(composer.getNode());
+ }
+ return documents;
+ }
+
+ private List<Node> canonical_compose_all(InputStream file) {
+ Reader reader = new Reader(new UnicodeReader(file));
+ StringBuffer buffer = new StringBuffer();
+ while (reader.peek() != '\0') {
+ buffer.append(reader.peek());
+ reader.forward();
+ }
+ CanonicalParser parser = new CanonicalParser(buffer.toString());
+ Composer composer = new Composer(parser, new Resolver());
+ List<Node> documents = new LinkedList<Node>();
+ while (composer.checkNode()) {
+ documents.add(composer.getNode());
+ }
+ return documents;
+ }
+
+ class MyLoader extends Loader {
+ public MyLoader() {
+ super(new MyConstructor());
+ }
+ }
+
+ class CanonicalLoader extends Loader {
+ public CanonicalLoader() {
+ super(new MyConstructor());
+ }
+
+ @Override
+ public Iterable<Object> loadAll(java.io.Reader yaml) {
+ Reader reader = new Reader(yaml);
+ StringBuffer buffer = new StringBuffer();
+ while (reader.peek() != '\0') {
+ buffer.append(reader.peek());
+ reader.forward();
+ }
+ CanonicalParser parser = new CanonicalParser(buffer.toString());
+ Composer composer = new Composer(parser, resolver);
+ this.constructor.setComposer(composer);
+ Iterator<Object> result = new Iterator<Object>() {
+ public boolean hasNext() {
+ return constructor.checkData();
+ }
+
+ public Object next() {
+ return constructor.getData();
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ return new YamlIterable(result);
+ }
+
+ private class YamlIterable implements Iterable<Object> {
+ private Iterator<Object> iterator;
+
+ public YamlIterable(Iterator<Object> iterator) {
+ this.iterator = iterator;
+ }
+
+ public Iterator<Object> iterator() {
+ return iterator;
+ }
+
+ }
+
+ }
+
+ private class MyConstructor extends Constructor {
+ public MyConstructor() {
+ this.yamlConstructors.put(null, new ConstructUndefined());
+ }
+
+ private class ConstructUndefined implements Construct {
+ public Object construct(Node node) {
+ return constructScalar((ScalarNode) node);
+ }
+ }
+ }
+
+ public void testConstructor() throws IOException {
+ File[] files = getStreamsByExtension(".data", true);
+ assertTrue("No test files found.", files.length > 0);
+ Yaml myYaml = new Yaml(new MyLoader());
+ Yaml canonicalYaml = new Yaml(new CanonicalLoader());
+ for (File file : files) {
+ try {
+ Iterable<Object> documents1 = myYaml.loadAll(new FileInputStream(file));
+ int index = file.getAbsolutePath().lastIndexOf('.');
+ String canonicalName = file.getAbsolutePath().substring(0, index) + ".canonical";
+ File canonical = new File(canonicalName);
+ Iterable<Object> documents2 = canonicalYaml.loadAll(new FileInputStream(canonical));
+ Iterator<Object> iter2 = documents2.iterator();
+ for (Object object1 : documents1) {
+ Object object2 = iter2.next();
+ if (object2 != null) {
+ assertFalse(System.identityHashCode(object1) == System
+ .identityHashCode(object2));
+ }
+ assertEquals("" + object1, object1, object2);
+ }
+ } catch (Exception e) {
+ System.out.println("Failed File: " + file);
+ // fail("Failed File: " + file + "; " + e.getMessage());
+ throw new RuntimeException(e);
+ }
+ }
+ }
+}
diff --git a/src/test/java/org/pyyaml/PyTokensTest.java b/src/test/java/org/pyyaml/PyTokensTest.java
new file mode 100644
index 00000000..42f65948
--- /dev/null
+++ b/src/test/java/org/pyyaml/PyTokensTest.java
@@ -0,0 +1,140 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.pyyaml;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.yaml.snakeyaml.reader.Reader;
+import org.yaml.snakeyaml.reader.UnicodeReader;
+import org.yaml.snakeyaml.scanner.Scanner;
+import org.yaml.snakeyaml.scanner.ScannerImpl;
+import org.yaml.snakeyaml.tokens.AliasToken;
+import org.yaml.snakeyaml.tokens.AnchorToken;
+import org.yaml.snakeyaml.tokens.BlockEndToken;
+import org.yaml.snakeyaml.tokens.BlockEntryToken;
+import org.yaml.snakeyaml.tokens.BlockMappingStartToken;
+import org.yaml.snakeyaml.tokens.BlockSequenceStartToken;
+import org.yaml.snakeyaml.tokens.DirectiveToken;
+import org.yaml.snakeyaml.tokens.DocumentEndToken;
+import org.yaml.snakeyaml.tokens.DocumentStartToken;
+import org.yaml.snakeyaml.tokens.FlowEntryToken;
+import org.yaml.snakeyaml.tokens.FlowMappingEndToken;
+import org.yaml.snakeyaml.tokens.FlowMappingStartToken;
+import org.yaml.snakeyaml.tokens.FlowSequenceEndToken;
+import org.yaml.snakeyaml.tokens.FlowSequenceStartToken;
+import org.yaml.snakeyaml.tokens.KeyToken;
+import org.yaml.snakeyaml.tokens.ScalarToken;
+import org.yaml.snakeyaml.tokens.StreamEndToken;
+import org.yaml.snakeyaml.tokens.StreamStartToken;
+import org.yaml.snakeyaml.tokens.TagToken;
+import org.yaml.snakeyaml.tokens.Token;
+import org.yaml.snakeyaml.tokens.ValueToken;
+
+/**
+ * @see imported from PyYAML
+ */
+public class PyTokensTest extends PyImportTest {
+
+ @SuppressWarnings("unchecked")
+ public void testTokens() throws FileNotFoundException {
+ Map<Class, String> replaces = new HashMap<Class, String>();
+ replaces.put(DirectiveToken.class, "%");
+ replaces.put(DocumentStartToken.class, "---");
+ replaces.put(DocumentEndToken.class, "...");
+ replaces.put(AliasToken.class, "*");
+ replaces.put(AnchorToken.class, "&");
+ replaces.put(TagToken.class, "!");
+ replaces.put(ScalarToken.class, "_");
+ replaces.put(BlockSequenceStartToken.class, "[[");
+ replaces.put(BlockMappingStartToken.class, "{{");
+ replaces.put(BlockEndToken.class, "]}");
+ replaces.put(FlowSequenceStartToken.class, "[");
+ replaces.put(FlowSequenceEndToken.class, "]");
+ replaces.put(FlowMappingStartToken.class, "{");
+ replaces.put(FlowMappingEndToken.class, "}");
+ replaces.put(BlockEntryToken.class, ",");
+ replaces.put(FlowEntryToken.class, ",");
+ replaces.put(KeyToken.class, "?");
+ replaces.put(ValueToken.class, ":");
+ //
+ File[] tokensFiles = getStreamsByExtension(".tokens");
+ assertTrue("No test files found.", tokensFiles.length > 0);
+ for (int i = 0; i < tokensFiles.length; i++) {
+ String name = tokensFiles[i].getName();
+ int position = name.lastIndexOf('.');
+ String dataName = name.substring(0, position) + ".data";
+ //
+ String tokenFileData = getResource(name);
+ String[] split = tokenFileData.split("\\s+");
+ List<String> tokens2 = new LinkedList<String>();
+ for (int j = 0; j < split.length; j++) {
+ tokens2.add(split[j]);
+ }
+ //
+ List<String> tokens1 = new LinkedList<String>();
+ Reader reader = new Reader(new UnicodeReader(new FileInputStream(
+ getFileByName(dataName))));
+ Scanner scanner = new ScannerImpl(reader);
+ try {
+ while (scanner.checkToken(new ArrayList<Class<? extends Token>>())) {
+ Token token = scanner.getToken();
+ if (!(token instanceof StreamStartToken || token instanceof StreamEndToken)) {
+ String replacement = replaces.get(token.getClass());
+ tokens1.add(replacement);
+ }
+ }
+ // System.out.println("File name: \n" +
+ // tokensFiles[i].getName());
+ // Iterator iter = tokens2.iterator();
+ // for (String string : tokens1) {
+ // String str2 = (String) iter.next();
+ // System.out.println(string + "=" + str2);
+ // }
+ assertEquals(tokenFileData, tokens1.size(), tokens2.size());
+ assertEquals(tokens1, tokens2);
+ } catch (RuntimeException e) {
+ System.out.println("File name: \n" + tokensFiles[i].getName());
+ String data = getResource(tokensFiles[i].getName());
+ System.out.println("Data: \n" + data);
+ System.out.println("Tokens:");
+ for (String token : tokens1) {
+ System.out.println(token);
+ }
+ fail("Cannot scan: " + tokensFiles[i]);
+ }
+ }
+ }
+
+ public void testScanner() throws FileNotFoundException {
+ File[] files = getStreamsByExtension(".data", true);
+ assertTrue("No test files found.", files.length > 0);
+ for (File file : files) {
+ List<String> tokens = new LinkedList<String>();
+ Reader reader = new Reader(new UnicodeReader(new FileInputStream(file)));
+ Scanner scanner = new ScannerImpl(reader);
+ try {
+ while (scanner.checkToken(new ArrayList<Class<? extends Token>>())) {
+ Token token = scanner.getToken();
+ tokens.add(token.getClass().getName());
+ }
+ } catch (RuntimeException e) {
+ System.out.println("File name: \n" + file.getName());
+ String data = getResource(file.getName());
+ System.out.println("Data: \n" + data);
+ System.out.println("Tokens:");
+ for (String token : tokens) {
+ System.out.println(token);
+ }
+ fail("Cannot scan: " + file + "; " + e.getMessage());
+ }
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/Address.java b/src/test/java/org/yaml/snakeyaml/Address.java
new file mode 100644
index 00000000..e18fb5d0
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/Address.java
@@ -0,0 +1,11 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml;
+
+public class Address {
+ public String lines;
+ public String city;
+ public String state;
+ public String postal;
+} \ No newline at end of file
diff --git a/src/test/java/org/yaml/snakeyaml/BinaryBean.java b/src/test/java/org/yaml/snakeyaml/BinaryBean.java
new file mode 100644
index 00000000..026b1519
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/BinaryBean.java
@@ -0,0 +1,26 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml;
+
+public class BinaryBean {
+ byte[] data;
+ int id;
+
+ public byte[] getData() {
+ return data;
+ }
+
+ public void setData(byte[] data) {
+ this.data = data;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+} \ No newline at end of file
diff --git a/src/test/java/org/yaml/snakeyaml/BinaryJavaBeanTest.java b/src/test/java/org/yaml/snakeyaml/BinaryJavaBeanTest.java
new file mode 100644
index 00000000..7121c375
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/BinaryJavaBeanTest.java
@@ -0,0 +1,20 @@
+package org.yaml.snakeyaml;
+
+import junit.framework.TestCase;
+
+public class BinaryJavaBeanTest extends TestCase {
+ public void testBeanTest() {
+ BinaryBean bean = new BinaryBean();
+ bean.setId(1);
+ byte[] bytes = new byte[] { 1, 7, 9, 31, 65 };
+ bean.setData(bytes);
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(bean);
+ String etalon = "!!org.yaml.snakeyaml.BinaryBean\ndata: !!binary |-\n AQcJH0E=\nid: 1\n";
+ assertEquals(etalon, output);
+ // load
+ BinaryBean bean2 = (BinaryBean) yaml.load(output);
+ assertEquals(1, bean2.getId());
+ assertEquals(new String(bytes), new String(bean2.getData()));
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/Chapter2_1Test.java b/src/test/java/org/yaml/snakeyaml/Chapter2_1Test.java
new file mode 100644
index 00000000..c66dfe0e
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/Chapter2_1Test.java
@@ -0,0 +1,96 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml;
+
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+/**
+ * Test Chapter 2.1 from the YAML specification
+ *
+ * @author py4fun
+ * @see http://yaml.org/spec/1.1/
+ */
+public class Chapter2_1Test extends TestCase {
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_1() {
+ YamlDocument document = new YamlDocument("example2_1.yaml");
+ List<String> list = (List<String>) document.getNativeData();
+ assertEquals(3, list.size());
+ assertEquals("Mark McGwire", list.get(0));
+ assertEquals("Sammy Sosa", list.get(1));
+ assertEquals("Ken Griffey", list.get(2));
+ assertEquals("[Mark McGwire, Sammy Sosa, Ken Griffey]\n", document.getPresentation());
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_2() {
+ YamlDocument document = new YamlDocument("example2_2.yaml");
+ Map<String, Object> map = (Map<String, Object>) document.getNativeData();
+ assertEquals(3, map.size());
+ assertEquals("Expect 65 to be a Integer", Integer.class, map.get("hr").getClass());
+ assertEquals(new Integer(65), map.get("hr"));
+ assertEquals(new Float(0.278), new Float("0.278"));
+ assertEquals("Expect 0.278 to be a Float", Double.class, map.get("avg").getClass());
+ assertEquals(new Double(0.278), map.get("avg"));
+ assertEquals("Expect 147 to be an Integer", Integer.class, map.get("rbi").getClass());
+ assertEquals(new Integer(147), map.get("rbi"));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_3() {
+ YamlDocument document = new YamlDocument("example2_3.yaml");
+ Map<String, List<String>> map = (Map<String, List<String>>) document.getNativeData();
+ assertEquals(2, map.size());
+ List<String> list1 = map.get("american");
+ assertEquals(3, list1.size());
+ assertEquals("Boston Red Sox", list1.get(0));
+ assertEquals("Detroit Tigers", list1.get(1));
+ assertEquals("New York Yankees", list1.get(2));
+ List<String> list2 = map.get("national");
+ assertEquals(3, list2.size());
+ assertEquals("New York Mets", list2.get(0));
+ assertEquals("Chicago Cubs", list2.get(1));
+ assertEquals("Atlanta Braves", list2.get(2));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_4() {
+ YamlDocument document = new YamlDocument("example2_4.yaml");
+ List<Map<String, Object>> list = (List<Map<String, Object>>) document.getNativeData();
+ assertEquals(2, list.size());
+ Map<String, Object> map1 = list.get(0);
+ assertEquals(3, map1.size());
+ assertEquals("Mark McGwire", map1.get("name"));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_5() {
+ YamlDocument document = new YamlDocument("example2_5.yaml");
+ List<List<Object>> list = (List<List<Object>>) document.getNativeData();
+ assertEquals(3, list.size());
+ List<Object> list1 = list.get(0);
+ assertEquals(3, list1.size());
+ assertEquals("name", list1.get(0));
+ assertEquals("hr", list1.get(1));
+ assertEquals("avg", list1.get(2));
+ assertEquals(3, list.get(1).size());
+ assertEquals(3, list.get(2).size());
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_6() {
+ YamlDocument document = new YamlDocument("example2_6.yaml");
+ Map<String, Map<String, Object>> map = (Map<String, Map<String, Object>>) document
+ .getNativeData();
+ assertEquals(2, map.size());
+ Map<String, Object> map1 = map.get("Mark McGwire");
+ assertEquals(2, map1.size());
+ Map<String, Object> map2 = map.get("Sammy Sosa");
+ assertEquals(2, map2.size());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/Chapter2_2Test.java b/src/test/java/org/yaml/snakeyaml/Chapter2_2Test.java
new file mode 100644
index 00000000..1e166ee7
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/Chapter2_2Test.java
@@ -0,0 +1,101 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml;
+
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+/**
+ * Test Chapter 2.2 from the YAML specification
+ *
+ * @author py4fun
+ * @see http://yaml.org/spec/1.1/
+ */
+public class Chapter2_2Test extends TestCase {
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_7() {
+ YamlStream resource = new YamlStream("example2_7.yaml");
+ List<Object> list = (List<Object>) resource.getNativeData();
+ assertEquals(2, list.size());
+ List<String> list1 = (List<String>) list.get(0);
+ assertEquals(3, list1.size());
+ assertEquals("Mark McGwire", list1.get(0));
+ assertEquals("Sammy Sosa", list1.get(1));
+ assertEquals("Ken Griffey", list1.get(2));
+ List<String> list2 = (List<String>) list.get(1);
+ assertEquals(2, list2.size());
+ assertEquals("Chicago Cubs", list2.get(0));
+ assertEquals("St Louis Cardinals", list2.get(1));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_8() {
+ YamlStream resource = new YamlStream("example2_8.yaml");
+ List<Object> list = (List<Object>) resource.getNativeData();
+ assertEquals(2, list.size());
+ Map<String, String> map1 = (Map<String, String>) list.get(0);
+ assertEquals(3, map1.size());
+ assertEquals(new Integer(72200), map1.get("time"));
+ assertEquals("Sammy Sosa", map1.get("player"));
+ assertEquals("strike (miss)", map1.get("action"));
+ Map<String, String> map2 = (Map<String, String>) list.get(1);
+ assertEquals(3, map2.size());
+ assertEquals(new Integer(72227), map2.get("time"));
+ assertEquals("Sammy Sosa", map2.get("player"));
+ assertEquals("grand slam", map2.get("action"));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_9() {
+ YamlDocument document = new YamlDocument("example2_9.yaml");
+ Map<String, Object> map = (Map<String, Object>) document.getNativeData();
+ assertEquals(map.toString(), 2, map.size());
+ List<String> list1 = (List<String>) map.get("hr");
+ assertEquals(2, list1.size());
+ assertEquals("Mark McGwire", list1.get(0));
+ assertEquals("Sammy Sosa", list1.get(1));
+ List<String> list2 = (List<String>) map.get("rbi");
+ assertEquals(2, list2.size());
+ assertEquals("Sammy Sosa", list2.get(0));
+ assertEquals("Ken Griffey", list2.get(1));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_10() {
+ YamlDocument document = new YamlDocument("example2_10.yaml");
+ Map<String, Object> map = (Map<String, Object>) document.getNativeData();
+ assertEquals("Examples 2.9 and 2.10 must be identical.",
+ new YamlDocument("example2_9.yaml").getNativeData(), map);
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_11() {
+ YamlDocument document = new YamlDocument("example2_11.yaml");
+ Map<Object, Object> map = (Map<Object, Object>) document.getNativeData();
+ assertEquals(2, map.size());
+ for (Object key : map.keySet()) {
+ List<String> list = (List<String>) key;
+ assertEquals(2, list.size());
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_12() {
+ YamlDocument document = new YamlDocument("example2_12.yaml");
+ List<Map<Object, Object>> list = (List<Map<Object, Object>>) document.getNativeData();
+ assertEquals(3, list.size());
+ Map map1 = (Map) list.get(0);
+ assertEquals(2, map1.size());
+ assertEquals("Super Hoop", map1.get("item"));
+ Map map2 = (Map) list.get(1);
+ assertEquals(2, map2.size());
+ assertEquals("Basketball", map2.get("item"));
+ Map map3 = (Map) list.get(2);
+ assertEquals(2, map3.size());
+ assertEquals("Big Shoes", map3.get("item"));
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/Chapter2_3Test.java b/src/test/java/org/yaml/snakeyaml/Chapter2_3Test.java
new file mode 100644
index 00000000..74d9b537
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/Chapter2_3Test.java
@@ -0,0 +1,120 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+/**
+ * Test Chapter 2.3 from the YAML specification
+ *
+ * @author py4fun
+ * @see http://yaml.org/spec/1.1/
+ */
+public class Chapter2_3Test extends TestCase {
+
+ public void testExample_2_13() {
+ YamlDocument document = new YamlDocument("example2_13.yaml");
+ String data = (String) document.getNativeData();
+ assertEquals("\\//||\\/||\n// || ||__\n", data);
+ }
+
+ public void testExample_2_14() {
+ YamlDocument document = new YamlDocument("example2_14.yaml");
+ String data = (String) document.getNativeData();
+ assertEquals("Mark McGwire's year was crippled by a knee injury.", data);
+ }
+
+ public void testExample_2_15() {
+ String etalon = "Sammy Sosa completed another fine season with great stats.\n\n 63 Home Runs\n 0.288 Batting Average\n\nWhat a year!\n";
+ InputStream input = YamlDocument.class.getClassLoader().getResourceAsStream(
+ YamlDocument.ROOT + "example2_15.yaml");
+ Yaml yaml = new Yaml();
+ String data = (String) yaml.load(input);
+ assertEquals(etalon, data);
+ //
+ String dumped = yaml.dump(data);
+ assertTrue(dumped.contains("Sammy Sosa completed another fine season with great stats"));
+ assertEquals("Must be splitted into 2 lines.", 2, dumped.split("\n").length);
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_16() {
+ YamlDocument document = new YamlDocument("example2_16.yaml");
+ Map<String, String> map = (Map<String, String>) document.getNativeData();
+ assertEquals(map.toString(), 3, map.size());
+ assertEquals("Mark McGwire", map.get("name"));
+ assertEquals("Mark set a major league home run record in 1998.\n", map
+ .get("accomplishment"));
+ assertEquals("65 Home Runs\n0.278 Batting Average\n", map.get("stats"));
+
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_17() throws IOException {
+ YamlDocument document = new YamlDocument("example2_17.yaml", false);
+ Map<String, String> map = (Map<String, String>) document.getNativeData();
+ assertEquals(map.toString(), 6, map.size());
+ assertEquals("Sosa did fine.\u263A", map.get("unicode"));
+ assertEquals("\b1998\t1999\t2000\n", map.get("control"));
+ assertEquals("\r\n is \r\n", map.get("hexesc"));
+ assertEquals("\"Howdy!\" he cried.", map.get("single"));
+ assertEquals(" # not a 'comment'.", map.get("quoted"));
+ assertEquals("|\\-*-/|", map.get("tie-fighter"));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_17_unicode() {
+ YamlDocument document = new YamlDocument("example2_17_unicode.yaml");
+ Map<String, String> map = (Map<String, String>) document.getNativeData();
+ assertEquals("Sosa did fine.\u263A", map.get("unicode"));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_17_control() {
+ YamlDocument document = new YamlDocument("example2_17_control.yaml", false);
+ Map<String, String> map = (Map<String, String>) document.getNativeData();
+ assertEquals("\b1998\t1999\t2000\n", map.get("control"));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_17_hexesc() {
+ YamlDocument document = new YamlDocument("example2_17_hexesc.yaml");
+ Map<String, String> map = (Map<String, String>) document.getNativeData();
+ assertEquals("\r\n is \r\n", map.get("hexesc"));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_17_single() {
+ YamlDocument document = new YamlDocument("example2_17_single.yaml");
+ Map<String, String> map = (Map<String, String>) document.getNativeData();
+ assertEquals("\"Howdy!\" he cried.", map.get("single"));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_17_quoted() {
+ YamlDocument document = new YamlDocument("example2_17_quoted.yaml");
+ Map<String, String> map = (Map<String, String>) document.getNativeData();
+ assertEquals(" # not a 'comment'.", map.get("quoted"));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_17_tie_fighter() {
+ YamlDocument document = new YamlDocument("example2_17_tie_fighter.yaml");
+ Map<String, String> map = (Map<String, String>) document.getNativeData();
+ assertEquals("|\\-*-/|", map.get("tie-fighter"));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_18() throws IOException {
+ YamlDocument document = new YamlDocument("example2_18.yaml");
+ Map<String, String> map = (Map<String, String>) document.getNativeData();
+ assertEquals(map.toString(), 2, map.size());
+ assertEquals("This unquoted scalar spans many lines.", map.get("plain"));
+ assertEquals("So does this quoted scalar.\n", map.get("quoted"));
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/Chapter2_4Test.java b/src/test/java/org/yaml/snakeyaml/Chapter2_4Test.java
new file mode 100644
index 00000000..2a2ce53c
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/Chapter2_4Test.java
@@ -0,0 +1,171 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TimeZone;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.constructor.Construct;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.ScalarNode;
+
+/**
+ * Test Chapter 2.4 from the YAML specification
+ *
+ * @author py4fun
+ * @see http://yaml.org/spec/1.1/
+ */
+public class Chapter2_4Test extends TestCase {
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_19() {
+ YamlDocument document = new YamlDocument("example2_19.yaml");
+ Map<String, Object> map = (Map<String, Object>) document.getNativeData();
+ assertEquals(5, map.size());
+ assertEquals("Expect 12345 to be an Integer.", Integer.class, map.get("canonical")
+ .getClass());
+ assertEquals(new Integer(12345), map.get("canonical"));
+ assertEquals(new Integer(12345), map.get("decimal"));
+ assertEquals(new Integer(3 * 3600 + 25 * 60 + 45), map.get("sexagesimal"));
+ assertEquals(new Integer(014), map.get("octal"));
+ assertEquals(new Integer(0xC), map.get("hexadecimal"));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_20() {
+ YamlDocument document = new YamlDocument("example2_20.yaml");
+ Map<String, Object> map = (Map<String, Object>) document.getNativeData();
+ assertEquals(6, map.size());
+ assertEquals("Expect '1.23015e+3' to be a Double.", Double.class, map.get("canonical")
+ .getClass());
+ assertEquals(new Double(1230.15), map.get("canonical"));
+ assertEquals(new Double(12.3015e+02), map.get("exponential"));
+ assertEquals(new Double(20 * 60 + 30.15), map.get("sexagesimal"));
+ assertEquals(new Double(1230.15), map.get("fixed"));
+ assertEquals(Double.NEGATIVE_INFINITY, map.get("negative infinity"));
+ assertEquals(Double.NaN, map.get("not a number"));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_21() {
+ YamlDocument document = new YamlDocument("example2_21.yaml");
+ Map<String, Object> map = (Map<String, Object>) document.getNativeData();
+ assertEquals(4, map.size());
+ assertNull("'~' must be parsed as 'null': " + map.get(null), map.get(null));
+ assertTrue((Boolean) map.get(Boolean.TRUE));
+ assertFalse((Boolean) map.get(Boolean.FALSE));
+ assertEquals("12345", map.get("string"));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_22() {
+ YamlDocument document = new YamlDocument("example2_22.yaml");
+ Map<String, Object> map = (Map<String, Object>) document.getNativeData();
+ assertEquals(4, map.size());
+ assertEquals("Expect '2001-12-15T02:59:43.1Z' to be a Date.", Date.class, map.get(
+ "canonical").getClass());
+ Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
+ cal.clear();
+ cal.set(Calendar.YEAR, 2001);
+ cal.set(Calendar.MONTH, 11); // Java's months are zero-based...
+ cal.set(Calendar.DAY_OF_MONTH, 15);
+ cal.set(Calendar.HOUR_OF_DAY, 2);
+ cal.set(Calendar.MINUTE, 59);
+ cal.set(Calendar.SECOND, 43);
+ cal.set(Calendar.MILLISECOND, 100);
+ Date date = cal.getTime();
+ assertEquals(date, map.get("canonical"));
+ assertEquals("Expect '2001-12-14t21:59:43.10-05:00' to be a Date.", Date.class, map.get(
+ "iso8601").getClass());
+ assertEquals("Expect '2001-12-14 21:59:43.10 -5' to be a Date.", Date.class, map.get(
+ "spaced").getClass());
+ assertEquals("Expect '2002-12-14' to be a Date.", Date.class, map.get("date").getClass());
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_23_non_date() {
+ try {
+ YamlDocument document = new YamlDocument("example2_23_non_date.yaml");
+ Map<String, Object> map = (Map<String, Object>) document.getNativeData();
+ assertEquals(1, map.size());
+ assertEquals("2002-04-28", map.get("not-date"));
+ } catch (RuntimeException e) {
+ fail("Cannot parse '!!str': 'not-date: !!str 2002-04-28'");
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_23_picture() throws Exception {
+ YamlDocument document = new YamlDocument("example2_23_picture.yaml", false);
+ Map<String, Object> map = (Map<String, Object>) document.getNativeData();
+ assertEquals(1, map.size());
+ byte[] picture = (byte[]) map.get("picture");
+ assertEquals((byte) 'G', picture[0]);
+ assertEquals((byte) 'I', picture[1]);
+ assertEquals((byte) 'F', picture[2]);
+ }
+
+ class SomethingConstructor extends Constructor {
+ public SomethingConstructor() {
+ this.yamlConstructors.put("!something", new ConstructSomething());
+ }
+
+ private class ConstructSomething implements Construct {
+ public Object construct(Node node) {
+ // convert to upper case
+ String val = (String) constructScalar((ScalarNode) node);
+ return val.toUpperCase().replace('\n', ' ').trim();
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_23() throws IOException {
+ YamlDocument document = new YamlDocument("example2_23.yaml", false,
+ new SomethingConstructor());
+ Map<String, Object> map = (Map<String, Object>) document.getNativeData();
+ assertEquals(3, map.size());
+ String special = (String) map.get("application specific tag");
+ assertEquals("THE SEMANTICS OF THE TAG ABOVE MAY BE DIFFERENT FOR DIFFERENT DOCUMENTS.",
+ special);
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_25() {
+ YamlDocument document = new YamlDocument("example2_25.yaml");
+ Set<String> set = (Set<String>) document.getNativeData();
+ assertEquals(3, set.size());
+ assertTrue(set.contains("Mark McGwire"));
+ assertTrue(set.contains("Sammy Sosa"));
+ assertTrue(set.contains("Ken Griff"));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_26() {
+ YamlDocument document = new YamlDocument("example2_26.yaml");
+ Map<String, String> map = (Map<String, String>) document.getNativeData();
+ assertEquals(3, map.size());
+ assertTrue(map instanceof LinkedHashMap);
+ assertEquals(new Integer(65), map.get("Mark McGwire"));
+ assertEquals(new Integer(63), map.get("Sammy Sosa"));
+ assertEquals(new Integer(58), map.get("Ken Griffy"));
+ List list = new ArrayList();
+ for (String key : map.keySet()) {
+ list.add(key);
+ }
+ assertEquals("Mark McGwire", list.get(0));
+ assertEquals("Sammy Sosa", list.get(1));
+ assertEquals("Ken Griffy", list.get(2));
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/Chapter2_5Test.java b/src/test/java/org/yaml/snakeyaml/Chapter2_5Test.java
new file mode 100644
index 00000000..d80890ff
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/Chapter2_5Test.java
@@ -0,0 +1,52 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml;
+
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+/**
+ * Test Chapter 2.5 from the YAML specification
+ *
+ * @author py4fun
+ * @see http://yaml.org/spec/1.1/
+ */
+public class Chapter2_5Test extends TestCase {
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_28() {
+ YamlStream resource = new YamlStream("example2_28.yaml");
+ List<Object> list = (List<Object>) resource.getNativeData();
+ assertEquals(3, list.size());
+ Map<String, Object> data0 = (Map<String, Object>) list.get(0);
+ Date date = (Date) data0.get("Time");
+ assertEquals("Date: " + date, 1006545702000L, date.getTime());
+ assertEquals("ed", data0.get("User"));
+ assertEquals("This is an error message for the log file", data0.get("Warning"));
+ //
+ Map<String, Object> data1 = (Map<String, Object>) list.get(1);
+ Date date1 = (Date) data1.get("Time");
+ assertTrue("Date: " + date1, date1.after(date));
+ assertEquals("ed", data1.get("User"));
+ assertEquals("A slightly different error message.", data1.get("Warning"));
+ //
+ Map<String, Object> data3 = (Map<String, Object>) list.get(2);
+ Date date3 = (Date) data3.get("Date");
+ assertTrue("Date: " + date3, date3.after(date1));
+ assertEquals("ed", data3.get("User"));
+ assertEquals("Unknown variable \"bar\"", data3.get("Fatal"));
+ List<Map<String, String>> list3 = (List<Map<String, String>>) data3.get("Stack");
+ Map<String, String> map1 = list3.get(0);
+ assertEquals("TopClass.py", map1.get("file"));
+ assertEquals(new Integer(23), map1.get("line"));
+ assertEquals("x = MoreObject(\"345\\n\")\n", map1.get("code"));
+ Map<String, String> map2 = list3.get(1);
+ assertEquals("MoreClass.py", map2.get("file"));
+ assertEquals(new Integer(58), map2.get("line"));
+ assertEquals("foo = bar", map2.get("code"));
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/DumperOptionsTest.java b/src/test/java/org/yaml/snakeyaml/DumperOptionsTest.java
new file mode 100644
index 00000000..04d668d4
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/DumperOptionsTest.java
@@ -0,0 +1,261 @@
+package org.yaml.snakeyaml;
+
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.emitter.Emitter;
+import org.yaml.snakeyaml.error.YAMLException;
+
+public class DumperOptionsTest extends TestCase {
+
+ public void testDefaultStyle() {
+ DumperOptions options = new DumperOptions();
+ Yaml yaml = new Yaml(options);
+ assertEquals("abc\n", yaml.dump("abc"));
+ // string which looks like integer
+ assertEquals("'123'\n", yaml.dump("123"));
+ //
+ options.setDefaultStyle(DumperOptions.DefaultScalarStyle.DOUBLE_QUOTED);
+ yaml = new Yaml(options);
+ assertEquals("\"123\"\n", yaml.dump("123"));
+ //
+ options.setDefaultStyle(DumperOptions.DefaultScalarStyle.SINGLE_QUOTED);
+ yaml = new Yaml(options);
+ assertEquals("'123'\n", yaml.dump("123"));
+ //
+ options.setDefaultStyle(DumperOptions.DefaultScalarStyle.PLAIN);
+ yaml = new Yaml(options);
+ assertEquals("'123'\n", yaml.dump("123"));
+ assertEquals("abc\n", yaml.dump("abc"));
+ // null check
+ try {
+ options.setDefaultStyle(null);
+ fail("Null must not be accepted.");
+ } catch (NullPointerException e) {
+ assertEquals("Use DefaultScalarStyle enum.", e.getMessage());
+ }
+ }
+
+ public void testDefaultFlowStyle() {
+ Yaml yaml = new Yaml();
+ List<Integer> list = new LinkedList<Integer>();
+ list.add(1);
+ list.add(2);
+ list.add(3);
+ assertEquals("[1, 2, 3]\n", yaml.dump(list));
+ //
+ DumperOptions options = new DumperOptions();
+ options = new DumperOptions();
+ options.setDefaultFlowStyle(DumperOptions.DefaultFlowStyle.FLOW);
+ yaml = new Yaml(options);
+ assertEquals("[1, 2, 3]\n", yaml.dump(list));
+ //
+ options = new DumperOptions();
+ options.setDefaultFlowStyle(DumperOptions.DefaultFlowStyle.BLOCK);
+ yaml = new Yaml(options);
+ assertEquals("- 1\n- 2\n- 3\n", yaml.dump(list));
+ // null check
+ try {
+ options.setDefaultFlowStyle(null);
+ fail("Null must not be accepted.");
+ } catch (NullPointerException e) {
+ assertEquals("Use DefaultFlowStyle enum.", e.getMessage());
+ }
+ }
+
+ public void testDefaultFlowStyleNested() {
+ Yaml yaml = new Yaml();
+ List<Integer> list = new LinkedList<Integer>();
+ list.add(1);
+ list.add(2);
+ list.add(3);
+ Map<String, Object> map = new LinkedHashMap<String, Object>();
+ map.put("a", "b");
+ map.put("c", list);
+ assertEquals("a: b\nc: [1, 2, 3]\n", yaml.dump(map));
+ //
+ DumperOptions options = new DumperOptions();
+ options = new DumperOptions();
+ options.setDefaultFlowStyle(DumperOptions.DefaultFlowStyle.FLOW);
+ yaml = new Yaml(options);
+ assertEquals("{a: b, c: [1, 2, 3]}\n", yaml.dump(map));
+ //
+ options = new DumperOptions();
+ options.setDefaultFlowStyle(DumperOptions.DefaultFlowStyle.BLOCK);
+ yaml = new Yaml(options);
+ assertEquals("a: b\nc:\n- 1\n- 2\n- 3\n", yaml.dump(map));
+ }
+
+ public void testCanonical() {
+ Yaml yaml = new Yaml();
+ assertEquals("123\n", yaml.dump(123));
+ //
+ DumperOptions options = new DumperOptions();
+ options = new DumperOptions();
+ options.setCanonical(true);
+ yaml = new Yaml(options);
+ assertEquals("---\n!!int \"123\"\n", yaml.dump(123));
+ //
+ options = new DumperOptions();
+ options.setCanonical(false);
+ yaml = new Yaml(options);
+ assertEquals("123\n", yaml.dump(123));
+ }
+
+ public void testIndent() {
+ Yaml yaml = new Yaml();
+ List<Integer> list = new LinkedList<Integer>();
+ list.add(1);
+ list.add(2);
+ DumperOptions options = new DumperOptions();
+ options.setCanonical(true);
+ yaml = new Yaml(options);
+ assertEquals("---\n!!seq [\n !!int \"1\",\n !!int \"2\",\n]\n", yaml.dump(list));
+ //
+ options.setIndent(4);
+ yaml = new Yaml(options);
+ assertEquals("---\n!!seq [\n !!int \"1\",\n !!int \"2\",\n]\n", yaml.dump(list));
+ //
+ try {
+ options.setIndent(0);
+ fail();
+ } catch (YAMLException e) {
+ assertTrue(true);
+ }
+ try {
+ options.setIndent(-2);
+ fail();
+ } catch (YAMLException e) {
+ assertTrue(true);
+ }
+ try {
+ options.setIndent(11);
+ fail();
+ } catch (YAMLException e) {
+ assertTrue(true);
+ }
+ //
+ assertTrue(Emitter.MIN_INDENT > 0);
+ assertTrue(Emitter.MIN_INDENT < Emitter.MAX_INDENT);
+ assertTrue(Emitter.MAX_INDENT < 20);
+ }
+
+ public void testLineBreak() {
+ Yaml yaml = new Yaml();
+ List<Integer> list = new LinkedList<Integer>();
+ list.add(1);
+ list.add(2);
+ DumperOptions options = new DumperOptions();
+ options.setCanonical(true);
+ yaml = new Yaml(options);
+ assertEquals("---\n!!seq [\n !!int \"1\",\n !!int \"2\",\n]\n", yaml.dump(list));
+ //
+ options.setLineBreak(DumperOptions.LineBreak.WIN);
+ yaml = new Yaml(options);
+ String output = yaml.dump(list);
+ assertEquals("---\r\n!!seq [\r\n !!int \"1\",\r\n !!int \"2\",\r\n]\r\n", output);
+ // null check
+ try {
+ options.setLineBreak(null);
+ fail("Null must not be accepted.");
+ } catch (NullPointerException e) {
+ assertEquals("Specify line break.", e.getMessage());
+ }
+ }
+
+ public void testExplicitStart() {
+ Yaml yaml = new Yaml();
+ List<Integer> list = new LinkedList<Integer>();
+ list.add(1);
+ list.add(2);
+ list.add(3);
+ assertEquals("[1, 2, 3]\n", yaml.dump(list));
+ //
+ DumperOptions options = new DumperOptions();
+ options = new DumperOptions();
+ options.setExplicitStart(true);
+ yaml = new Yaml(options);
+ assertEquals("--- [1, 2, 3]\n", yaml.dump(list));
+ //
+ options.setExplicitEnd(true);
+ yaml = new Yaml(options);
+ assertEquals("--- [1, 2, 3]\n...\n", yaml.dump(list));
+ }
+
+ public void testVersion() {
+ Yaml yaml = new Yaml();
+ List<Integer> list = new LinkedList<Integer>();
+ list.add(1);
+ list.add(2);
+ list.add(3);
+ assertEquals("[1, 2, 3]\n", yaml.dump(list));
+ //
+ DumperOptions options = new DumperOptions();
+ options = new DumperOptions();
+ options.setVersion(DumperOptions.Version.V1_1);
+ yaml = new Yaml(options);
+ assertEquals("%YAML 1.1\n--- [1, 2, 3]\n", yaml.dump(list));
+ //
+ options.setVersion(DumperOptions.Version.V1_0);
+ yaml = new Yaml(options);
+ assertEquals("%YAML 1.0\n--- [1, 2, 3]\n", yaml.dump(list));
+ }
+
+ public void testTags() {
+ Yaml yaml = new Yaml();
+ List<Integer> list = new LinkedList<Integer>();
+ list.add(1);
+ list.add(2);
+ list.add(3);
+ assertEquals("[1, 2, 3]\n", yaml.dump(list));
+ //
+ DumperOptions options = new DumperOptions();
+ options = new DumperOptions();
+ Map<String, String> tags = new LinkedHashMap<String, String>();
+ tags.put("!foo!", "bar");
+ options.setTags(tags);
+ yaml = new Yaml(options);
+ assertEquals("%TAG !foo! bar\n--- [1, 2, 3]\n", yaml.dump(list));
+ //
+ options = new DumperOptions();
+ tags.put("!yaml!", "tag:yaml.org,2002:");
+ yaml = new Yaml(options);
+ assertEquals("foo\n", yaml.dump("foo"));
+ }
+
+ public void testAllowUnicode() {
+ Yaml yaml = new Yaml();
+ assertEquals("out: " + yaml.dump("\u00DCber"), "\u00DCber\n", yaml.dump("\u00DCber"));
+ //
+ DumperOptions options = new DumperOptions();
+ options = new DumperOptions();
+ options.setAllowUnicode(false);
+ yaml = new Yaml(options);
+ assertEquals("\"\\xdcber\"\n", yaml.dump("\u00DCber"));
+ }
+
+ public void testSetRootTag() {
+ DumperOptions options = new DumperOptions();
+ try {
+ options.setExplicitRoot(null);
+ fail("Root tag is required.");
+ } catch (NullPointerException e) {
+ assertEquals("Root tag must be specified.", e.getMessage());
+ }
+ }
+
+ public void testToString() {
+ DumperOptions.DefaultScalarStyle scalarStyle = DumperOptions.DefaultScalarStyle.LITERAL;
+ assertEquals("Scalar style: '|'", scalarStyle.toString());
+ //
+ DumperOptions.DefaultFlowStyle flowStyle = DumperOptions.DefaultFlowStyle.BLOCK;
+ assertEquals("Flow style: 'false'", flowStyle.toString());
+ //
+ DumperOptions.LineBreak lb = DumperOptions.LineBreak.LINUX;
+ assertEquals("Line break: LINUX", lb.toString());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/DumperTest.java b/src/test/java/org/yaml/snakeyaml/DumperTest.java
new file mode 100644
index 00000000..ddbab0ee
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/DumperTest.java
@@ -0,0 +1,82 @@
+package org.yaml.snakeyaml;
+
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+import java.io.IOException;
+import java.io.Writer;
+import java.util.LinkedList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+public class DumperTest extends TestCase {
+
+ public void testDump1() {
+ DumperOptions options = new DumperOptions();
+ options.setDefaultStyle(DumperOptions.DefaultScalarStyle.DOUBLE_QUOTED);
+ options.setExplicitStart(true);
+ options.setExplicitEnd(true);
+ List<Integer> list = new LinkedList<Integer>();
+ for (int i = 0; i < 3; i++) {
+ list.add(i);
+ }
+ Yaml yaml = new Yaml(options);
+ String output = yaml.dump(list);
+ assertEquals("---\n- !!int \"0\"\n- !!int \"1\"\n- !!int \"2\"\n...\n", output);
+ }
+
+ public void testDump2() {
+ DumperOptions options = new DumperOptions();
+ options.setExplicitStart(true);
+ List<Integer> list = new LinkedList<Integer>();
+ for (int i = 0; i < 3; i++) {
+ list.add(i);
+ }
+ Yaml yaml = new Yaml(options);
+ String output = yaml.dump(list);
+ assertEquals("--- [0, 1, 2]\n", output);
+ }
+
+ public void testDump3() {
+ DumperOptions options = new DumperOptions();
+ options.setDefaultStyle(DumperOptions.DefaultScalarStyle.SINGLE_QUOTED);
+ List<Integer> list = new LinkedList<Integer>();
+ for (int i = 0; i < 3; i++) {
+ list.add(i);
+ }
+ Yaml yaml = new Yaml(options);
+ String output = yaml.dump(list);
+ assertEquals("- !!int '0'\n- !!int '1'\n- !!int '2'\n", output);
+ }
+
+ public void testDumpException() {
+ Yaml yaml = new Yaml();
+ Writer writer = new ExceptionWriter1();
+ try {
+ yaml.dump("aaa1234567890", writer);
+ fail("Exception must be thrown.");
+ } catch (Exception e) {
+ assertEquals("java.io.IOException: write test failure.", e.getMessage());
+ }
+ }
+
+ private class ExceptionWriter1 extends Writer {
+ @Override
+ public void write(String str) throws IOException {
+ throw new IOException("write test failure.");
+ }
+
+ @Override
+ public void close() throws IOException {
+ }
+
+ @Override
+ public void flush() throws IOException {
+ }
+
+ @Override
+ public void write(char[] cbuf, int off, int len) throws IOException {
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/EnumBean.java b/src/test/java/org/yaml/snakeyaml/EnumBean.java
new file mode 100644
index 00000000..c1bfb523
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/EnumBean.java
@@ -0,0 +1,36 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml;
+
+import java.util.LinkedHashMap;
+
+public class EnumBean {
+ private int id;
+ private Suit suit;
+ private LinkedHashMap<Suit, Integer> map = new LinkedHashMap<Suit, Integer>();
+
+ public LinkedHashMap<Suit, Integer> getMap() {
+ return map;
+ }
+
+ public void setMap(LinkedHashMap<Suit, Integer> map) {
+ this.map = map;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public Suit getSuit() {
+ return suit;
+ }
+
+ public void setSuit(Suit suit) {
+ this.suit = suit;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/EnumTest.java b/src/test/java/org/yaml/snakeyaml/EnumTest.java
new file mode 100644
index 00000000..39dc0d93
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/EnumTest.java
@@ -0,0 +1,175 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.EnumMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.constructor.Constructor;
+
+public class EnumTest extends TestCase {
+ // Dumping
+ public void testDumpEnum() {
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(Suit.CLUBS);
+ assertEquals("!!org.yaml.snakeyaml.Suit 'CLUBS'\n", output);
+ }
+
+ public void testDumpEnumArray() {
+ DumperOptions options = new DumperOptions();
+ options.setDefaultFlowStyle(DumperOptions.DefaultFlowStyle.BLOCK);
+ Yaml yaml = new Yaml(options);
+ String output = yaml.dump(Suit.values());
+ assertEquals(
+ "- !!org.yaml.snakeyaml.Suit 'CLUBS'\n- !!org.yaml.snakeyaml.Suit 'DIAMONDS'\n- !!org.yaml.snakeyaml.Suit 'HEARTS'\n- !!org.yaml.snakeyaml.Suit 'SPADES'\n",
+ output);
+ }
+
+ public void testDumpEnumList() {
+ DumperOptions options = new DumperOptions();
+ options.setDefaultFlowStyle(DumperOptions.DefaultFlowStyle.BLOCK);
+ Yaml yaml = new Yaml(options);
+ List<Suit> list = Arrays.asList(Suit.values());
+ String output = yaml.dump(list);
+ assertEquals(
+ "- !!org.yaml.snakeyaml.Suit 'CLUBS'\n- !!org.yaml.snakeyaml.Suit 'DIAMONDS'\n- !!org.yaml.snakeyaml.Suit 'HEARTS'\n- !!org.yaml.snakeyaml.Suit 'SPADES'\n",
+ output);
+ }
+
+ public void testDumpEnumListNoAnchor() {
+ DumperOptions options = new DumperOptions();
+ options.setDefaultFlowStyle(DumperOptions.DefaultFlowStyle.BLOCK);
+ Yaml yaml = new Yaml(options);
+ List<Suit> list = new ArrayList<Suit>(3);
+ list.add(Suit.CLUBS);
+ list.add(Suit.DIAMONDS);
+ list.add(Suit.CLUBS);
+ String output = yaml.dump(list);
+ assertEquals(
+ "- !!org.yaml.snakeyaml.Suit 'CLUBS'\n- !!org.yaml.snakeyaml.Suit 'DIAMONDS'\n- !!org.yaml.snakeyaml.Suit 'CLUBS'\n",
+ output);
+ }
+
+ public void testDumpEnumMap() {
+ DumperOptions options = new DumperOptions();
+ options.setDefaultFlowStyle(DumperOptions.DefaultFlowStyle.BLOCK);
+ Yaml yaml = new Yaml(options);
+ Map<String, Suit> map = new LinkedHashMap<String, Suit>();
+ map.put("c", Suit.CLUBS);
+ map.put("d", Suit.DIAMONDS);
+ String output = yaml.dump(map);
+ assertEquals(
+ "c: !!org.yaml.snakeyaml.Suit 'CLUBS'\nd: !!org.yaml.snakeyaml.Suit 'DIAMONDS'\n",
+ output);
+ }
+
+ public void testDumpEnumMap2() {
+ DumperOptions options = new DumperOptions();
+ options.setDefaultFlowStyle(DumperOptions.DefaultFlowStyle.BLOCK);
+ Yaml yaml = new Yaml(options);
+ Map<Suit, Integer> map = new EnumMap<Suit, Integer>(Suit.class);
+ map.put(Suit.CLUBS, 0);
+ map.put(Suit.DIAMONDS, 123);
+ String output = yaml.dump(map);
+ assertEquals(
+ "!!org.yaml.snakeyaml.Suit 'CLUBS': 0\n!!org.yaml.snakeyaml.Suit 'DIAMONDS': 123\n",
+ output);
+ }
+
+ public void testDumpEnumBean() {
+ DumperOptions options = new DumperOptions();
+ options.setDefaultFlowStyle(DumperOptions.DefaultFlowStyle.BLOCK);
+ Yaml yaml = new Yaml(options);
+ EnumBean bean = new EnumBean();
+ bean.setId(17);
+ bean.setSuit(Suit.SPADES);
+ LinkedHashMap<Suit, Integer> map = new LinkedHashMap<Suit, Integer>();
+ map.put(Suit.CLUBS, 1);
+ map.put(Suit.DIAMONDS, 2);
+ bean.setMap(map);
+ String output = yaml.dump(bean);
+ assertEquals(
+ "!!org.yaml.snakeyaml.EnumBean\nid: 17\nmap:\n !!org.yaml.snakeyaml.Suit 'CLUBS': 1\n !!org.yaml.snakeyaml.Suit 'DIAMONDS': 2\nsuit: SPADES\n",
+ output);
+ }
+
+ // Loading
+ public void testLoadEnum() {
+ Yaml yaml = new Yaml();
+ Suit suit = (Suit) yaml.load("!!org.yaml.snakeyaml.Suit 'CLUBS'\n");
+ assertEquals(Suit.CLUBS, suit);
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testLoadEnumList() {
+ Yaml yaml = new Yaml();
+ List<Suit> list = (List<Suit>) yaml
+ .load("- !!org.yaml.snakeyaml.Suit 'CLUBS'\n- !!org.yaml.snakeyaml.Suit 'DIAMONDS'\n- !!org.yaml.snakeyaml.Suit 'HEARTS'\n- !!org.yaml.snakeyaml.Suit 'SPADES'");
+ assertEquals(4, list.size());
+ assertEquals(Suit.CLUBS, list.get(0));
+ assertEquals(Suit.DIAMONDS, list.get(1));
+ assertEquals(Suit.HEARTS, list.get(2));
+ assertEquals(Suit.SPADES, list.get(3));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testLoadEnumMap() {
+ Yaml yaml = new Yaml();
+ Map<Integer, Suit> map = (Map<Integer, Suit>) yaml
+ .load("1: !!org.yaml.snakeyaml.Suit 'HEARTS'\n2: !!org.yaml.snakeyaml.Suit 'DIAMONDS'");
+ assertEquals(2, map.size());
+ assertEquals(Suit.HEARTS, map.get(1));
+ assertEquals(Suit.DIAMONDS, map.get(2));
+ }
+
+ public void testLoadEnumBean() {
+ Yaml yaml = new Yaml();
+ EnumBean bean = (EnumBean) yaml
+ .load("!!org.yaml.snakeyaml.EnumBean\nid: 174\nmap:\n !!org.yaml.snakeyaml.Suit 'CLUBS': 1\n !!org.yaml.snakeyaml.Suit 'DIAMONDS': 2\nsuit: CLUBS");
+
+ LinkedHashMap<Suit, Integer> map = new LinkedHashMap<Suit, Integer>();
+ map.put(Suit.CLUBS, 1);
+ map.put(Suit.DIAMONDS, 2);
+
+ assertEquals(Suit.CLUBS, bean.getSuit());
+ assertEquals(174, bean.getId());
+ assertEquals(map, bean.getMap());
+ }
+
+ public void testLoadEnumBean2() {
+ Constructor c = new Constructor();
+ TypeDescription td = new TypeDescription(EnumBean.class);
+ td.putMapPropertyType("map", Suit.class, Object.class);
+ c.addTypeDescription(td);
+ Yaml yaml = new Yaml(new Loader(c));
+ EnumBean bean = (EnumBean) yaml
+ .load("!!org.yaml.snakeyaml.EnumBean\nid: 174\nmap:\n CLUBS: 1\n DIAMONDS: 2\nsuit: CLUBS");
+
+ LinkedHashMap<Suit, Integer> map = new LinkedHashMap<Suit, Integer>();
+ map.put(Suit.CLUBS, 1);
+ map.put(Suit.DIAMONDS, 2);
+
+ assertEquals(Suit.CLUBS, bean.getSuit());
+ assertEquals(174, bean.getId());
+ assertEquals(map, bean.getMap());
+ }
+
+ public void testLoadWrongEnum() {
+ Yaml yaml = new Yaml();
+ try {
+ yaml
+ .load("1: !!org.yaml.snakeyaml.Suit 'HEARTS'\n2: !!org.yaml.snakeyaml.Suit 'KOSYR'");
+ fail("KOSYR is not Suit");
+ } catch (Exception e) {
+ assertTrue("KOSYR must be reported", e.getMessage().contains(
+ "Unable to find enum value 'KOSYR' for enum"));
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/Example2_24Test.java b/src/test/java/org/yaml/snakeyaml/Example2_24Test.java
new file mode 100644
index 00000000..fbb0e214
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/Example2_24Test.java
@@ -0,0 +1,234 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.constructor.Construct;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.nodes.MappingNode;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.SequenceNode;
+import org.yaml.snakeyaml.representer.Represent;
+import org.yaml.snakeyaml.representer.Representer;
+
+/**
+ * Test Example 2.24 from the YAML specification
+ *
+ * @author py4fun
+ * @see http://yaml.org/spec/1.1/
+ */
+public class Example2_24Test extends TestCase {
+ class MyConstructor extends Constructor {
+ public MyConstructor() {
+ this.yamlConstructors.put("tag:clarkevans.com,2002:shape", new ConstructShape());
+ this.yamlConstructors.put("tag:clarkevans.com,2002:circle", new ConstructCircle());
+ this.yamlConstructors.put("tag:clarkevans.com,2002:line", new ConstructLine());
+ this.yamlConstructors.put("tag:clarkevans.com,2002:label", new ConstructLabel());
+ }
+
+ private class ConstructShape implements Construct {
+ @SuppressWarnings("unchecked")
+ public Object construct(Node node) {
+ SequenceNode snode = (SequenceNode) node;
+ List<Entity> values = (List<Entity>) constructSequence(snode);
+ Shape shape = new Shape(values);
+ return shape;
+ }
+ }
+
+ private class ConstructCircle implements Construct {
+ @SuppressWarnings("unchecked")
+ public Object construct(Node node) {
+ MappingNode mnode = (MappingNode) node;
+ Map values = (Map) constructMapping(mnode);
+ Circle circle = new Circle((Map) values.get("center"), (Integer) values
+ .get("radius"));
+ return circle;
+ }
+ }
+
+ private class ConstructLine implements Construct {
+ @SuppressWarnings("unchecked")
+ public Object construct(Node node) {
+ MappingNode mnode = (MappingNode) node;
+ Map values = (Map) constructMapping(mnode);
+ Line line = new Line((Map) values.get("start"), (Map) values.get("finish"));
+ return line;
+ }
+ }
+
+ private class ConstructLabel implements Construct {
+ @SuppressWarnings("unchecked")
+ public Object construct(Node node) {
+ MappingNode mnode = (MappingNode) node;
+ Map values = (Map) constructMapping(mnode);
+ Label label = new Label((Map) values.get("start"), (Integer) values.get("color"),
+ (String) values.get("text"));
+ return label;
+ }
+ }
+ }
+
+ class MyRepresenter extends Representer {
+ public MyRepresenter() {
+ this.representers.put(Shape.class, new RepresentShape());
+ this.representers.put(Circle.class, new RepresentCircle());
+ this.representers.put(Line.class, new RepresentLine());
+ this.representers.put(Label.class, new RepresentLabel());
+ this.representers.put(HexInteger.class, new RepresentHex());
+ }
+
+ private class RepresentShape implements Represent {
+ public Node representData(Object data) {
+ Shape shape = (Shape) data;
+ List<Entity> value = shape.getEntities();
+ return representSequence("!shape", value, Boolean.FALSE);
+ }
+ }
+
+ private class RepresentCircle implements Represent {
+ public Node representData(Object data) {
+ Circle circle = (Circle) data;
+ Map<String, Object> map = new TreeMap<String, Object>();
+ map.put("center", circle.getCenter());
+ map.put("radius", circle.getRadius());
+ return representMapping("!circle", map, Boolean.FALSE);
+ }
+ }
+
+ private class RepresentLine implements Represent {
+ public Node representData(Object data) {
+ Line line = (Line) data;
+ Map<String, Object> map = new TreeMap<String, Object>();
+ map.put("start", line.getStart());
+ map.put("finish", line.getFinish());
+ return representMapping("!line", map, Boolean.FALSE);
+ }
+ }
+
+ private class RepresentLabel implements Represent {
+ public Node representData(Object data) {
+ Label label = (Label) data;
+ Map<String, Object> map = new TreeMap<String, Object>();
+ map.put("start", label.getStart());
+ map.put("color", new HexInteger(label.getColor()));
+ map.put("text", label.getText());
+ return representMapping("!label", map, Boolean.FALSE);
+ }
+ }
+
+ private class RepresentHex implements Represent {
+ public Node representData(Object data) {
+ HexInteger hex = (HexInteger) data;
+ return representScalar("tag:yaml.org,2002:int", "0x"
+ + Integer.toHexString(hex.getColor()).toUpperCase(), null);
+ }
+ }
+ }
+
+ private class HexInteger {
+ private Integer color;
+
+ public HexInteger(Integer color) {
+ this.color = color;
+ }
+
+ public Integer getColor() {
+ return color;
+ }
+ }
+
+ private class Shape {
+ private List<Entity> entities;
+
+ public List<Entity> getEntities() {
+ return entities;
+ }
+
+ public Shape(List<Entity> entities) {
+ this.entities = entities;
+ }
+ }
+
+ private class Entity {
+ }
+
+ private class Circle extends Entity {
+ private Map<String, Integer> center;
+ private Integer radius;
+
+ public Circle(Map<String, Integer> center, Integer radius) {
+ this.center = center;
+ this.radius = radius;
+ }
+
+ public Map<String, Integer> getCenter() {
+ return center;
+ }
+
+ public Integer getRadius() {
+ return radius;
+ }
+ }
+
+ private class Line extends Entity {
+ private Map<String, Integer> start;
+ private Map<String, Integer> finish;
+
+ public Line(Map<String, Integer> start, Map<String, Integer> finish) {
+ this.start = start;
+ this.finish = finish;
+ }
+
+ public Map<String, Integer> getStart() {
+ return start;
+ }
+
+ public Map<String, Integer> getFinish() {
+ return finish;
+ }
+ }
+
+ private class Label extends Entity {
+ private Map<String, Integer> start;
+ private Integer color;
+ private String text;
+
+ public Label(Map<String, Integer> start, Integer color, String text) {
+ this.start = start;
+ this.color = color;
+ this.text = text;
+ }
+
+ public Map<String, Integer> getStart() {
+ return start;
+ }
+
+ public Integer getColor() {
+ return color;
+ }
+
+ public String getText() {
+ return text;
+ }
+ }
+
+ public void testExample_2_24() throws IOException {
+ Loader loader = new Loader(new MyConstructor());
+ Yaml yaml = new Yaml(loader);
+ Shape shape = (Shape) yaml.load(Util.getLocalResource("specification/example2_24.yaml"));
+ assertNotNull(shape);
+ Dumper dumper = new Dumper(new MyRepresenter(), new DumperOptions());
+ yaml = new Yaml(dumper);
+ String output = yaml.dump(shape);
+ String etalon = Util.getLocalResource("specification/example2_24_dumped.yaml");
+ assertEquals(etalon, output);
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/Example2_27Test.java b/src/test/java/org/yaml/snakeyaml/Example2_27Test.java
new file mode 100644
index 00000000..ec56fff7
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/Example2_27Test.java
@@ -0,0 +1,35 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml;
+
+import java.io.IOException;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.constructor.Constructor;
+
+/**
+ * Test Example 2.27 from the YAML specification
+ *
+ * @author py4fun
+ * @see http://yaml.org/spec/1.1/
+ */
+public class Example2_27Test extends TestCase {
+
+ public void testExample_2_27() throws IOException {
+ Loader loader = new Loader(new Constructor(Invoice.class));
+ Yaml yaml = new Yaml(loader);
+ Invoice invoice = (Invoice) yaml.load(Util
+ .getLocalResource("specification/example2_27.yaml"));
+ assertNotNull(invoice);
+ Person billTo = invoice.billTo;
+ assertEquals("Dumars", billTo.family);
+ Dumper dumper = new Dumper(new DumperOptions());
+ yaml = new Yaml(dumper);
+ String output = yaml.dump(invoice);
+ System.out.println(output);
+ String etalon = Util.getLocalResource("specification/example2_27_dumped.yaml");
+ assertEquals(etalon, output);
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/Invoice.java b/src/test/java/org/yaml/snakeyaml/Invoice.java
new file mode 100644
index 00000000..66c585be
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/Invoice.java
@@ -0,0 +1,18 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml;
+
+import java.util.List;
+
+public class Invoice {
+ public Integer invoice; // invoice
+ public String date; // date
+ public Person billTo;// bill-to
+ public Person shipTo;// ship-to
+ public List<Product> product;
+ public Float tax;
+ public Float total;
+ public String comments;
+
+} \ No newline at end of file
diff --git a/src/test/java/org/yaml/snakeyaml/JavaBeanParserTest.java b/src/test/java/org/yaml/snakeyaml/JavaBeanParserTest.java
new file mode 100644
index 00000000..2f2f18de
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/JavaBeanParserTest.java
@@ -0,0 +1,95 @@
+package org.yaml.snakeyaml;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.StringReader;
+
+import junit.framework.TestCase;
+
+public class JavaBeanParserTest extends TestCase {
+
+ public void testLoadString() {
+ Bean bean = new Bean();
+ bean.setId(3);
+ bean.setName("Test me.");
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(bean);
+ assertEquals("!!org.yaml.snakeyaml.JavaBeanParserTest$Bean {id: 3, name: Test me.}\n",
+ output);
+ Bean parsed = JavaBeanParser.load(output, Bean.class);
+ assertEquals(3, parsed.getId());
+ assertEquals("Test me.", parsed.getName());
+ // Runtime definition is more important
+ Bean2 parsed2 = JavaBeanParser.load(output, Bean2.class);
+ assertEquals(3, parsed2.getId());
+ assertEquals("Test me.", parsed2.getName());
+ assertFalse(parsed2.isValid());
+ }
+
+ public void testLoadInputStream() {
+ String yaml = "!!org.yaml.snakeyaml.JavaBeanParserTest$Bean {id: 3, name: Test me.}\n";
+ InputStream input = new ByteArrayInputStream(yaml.getBytes());
+ Bean parsed = JavaBeanParser.load(input, Bean.class);
+ assertEquals(3, parsed.getId());
+ assertEquals("Test me.", parsed.getName());
+ }
+
+ public void testLoadReader() {
+ String yaml = "!!org.yaml.snakeyaml.JavaBeanParserTest$Bean {id: 3, name: Test me.}\n";
+ java.io.Reader input = new StringReader(yaml);
+ Bean parsed = JavaBeanParser.load(input, Bean.class);
+ assertEquals(3, parsed.getId());
+ assertEquals("Test me.", parsed.getName());
+ }
+
+ public static class Bean {
+ private String name;
+ private int id;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+ }
+
+ public static class Bean2 {
+ private String name;
+ private int id;
+ private boolean valid;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public boolean isValid() {
+ return valid;
+ }
+
+ public void setValid(boolean valid) {
+ this.valid = valid;
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/ParallelTest.java b/src/test/java/org/yaml/snakeyaml/ParallelTest.java
new file mode 100644
index 00000000..1de2f2b8
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/ParallelTest.java
@@ -0,0 +1,83 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml;
+
+import java.io.IOException;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.error.YAMLException;
+
+/**
+ * Test that Yaml instances are independent and can be used in multiple threads.
+ */
+public class ParallelTest extends TestCase {
+ private int progress = 0;
+ private int MAX = 5;
+
+ public void testPerfomance() throws IOException {
+ String doc = Util.getLocalResource("specification/example2_27.yaml");
+ for (int i = 0; i < MAX; i++) {
+ Worker worker = new Worker(i, doc);
+ Thread thread = new Thread(worker);
+ thread.start();
+ }
+ while (progress < MAX - 1) {
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ fail(e.getMessage());
+ }
+ }
+ }
+
+ private class Worker implements Runnable {
+ private int id;
+ private String doc;
+
+ public Worker(int id, String doc) {
+ this.id = id;
+ this.doc = doc;
+ }
+
+ public void run() {
+ System.out.println("Started: " + id);
+ Loader loader = new Loader(new Constructor(Invoice.class));
+ Yaml yaml = new Yaml(loader);
+ long time1 = System.currentTimeMillis();
+ int cycles = 200;
+ for (int i = 0; i < cycles; i++) {
+ Invoice invoice = (Invoice) yaml.load(doc);
+ assertNotNull(invoice);
+ }
+ long time2 = System.currentTimeMillis();
+ float duration = (time2 - time1) / (float) cycles;
+ System.out.println("Duration of " + id + " was " + duration + " ms/load.");
+ progress++;
+ }
+ }
+
+ public void testSharedLoader() throws IOException {
+ Loader loader = new Loader(new Constructor(Invoice.class));
+ new Yaml(loader);
+ try {
+ new Yaml(loader);
+ fail("Loader cannot be shared.");
+ } catch (YAMLException e) {
+ assertEquals("Loader cannot be shared.", e.getMessage());
+ }
+ }
+
+ public void testSharedDumper() throws IOException {
+ Dumper dumper = new Dumper(new DumperOptions());
+ new Yaml(dumper);
+ try {
+ new Yaml(dumper);
+ fail("Dumper cannot be shared.");
+ } catch (YAMLException e) {
+ assertEquals("Dumper cannot be shared.", e.getMessage());
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/Person.java b/src/test/java/org/yaml/snakeyaml/Person.java
new file mode 100644
index 00000000..d231a18e
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/Person.java
@@ -0,0 +1,10 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml;
+
+public class Person {
+ public String given;
+ public String family;
+ public Address address;
+} \ No newline at end of file
diff --git a/src/test/java/org/yaml/snakeyaml/Product.java b/src/test/java/org/yaml/snakeyaml/Product.java
new file mode 100644
index 00000000..1417a680
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/Product.java
@@ -0,0 +1,11 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml;
+
+public class Product {
+ public String sku;
+ public Integer quantity;
+ public String description;
+ public Float price;
+} \ No newline at end of file
diff --git a/src/test/java/org/yaml/snakeyaml/StressTest.java b/src/test/java/org/yaml/snakeyaml/StressTest.java
new file mode 100644
index 00000000..708366ad
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/StressTest.java
@@ -0,0 +1,60 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml;
+
+import java.io.IOException;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.constructor.Constructor;
+
+public class StressTest extends TestCase {
+ String doc;
+
+ public void setUp() throws IOException {
+ doc = Util.getLocalResource("specification/example2_27.yaml");
+ }
+
+ public void testPerformance() throws IOException {
+ long time1 = System.currentTimeMillis();
+ new Yaml(new Loader(new Constructor(Invoice.class)));
+ long time2 = System.currentTimeMillis();
+ float duration = time2 - time1;
+ System.out.println("Init was " + duration + " ms.");
+
+ Yaml yaml = new Yaml(new Loader(new Constructor(Invoice.class)));
+ time1 = System.currentTimeMillis();
+ yaml.load(doc);
+ time2 = System.currentTimeMillis();
+ duration = time2 - time1;
+ System.out.println("\nSingle load was " + duration + " ms.");
+
+ yaml = new Yaml(new Loader(new Constructor(Invoice.class)));
+ int[] range = new int[] { 1000, 2000 };
+ System.out.println("\nOne instance.");
+ for (int number : range) {
+ time1 = System.currentTimeMillis();
+ for (int i = 0; i < number; i++) {
+ yaml.load(doc);
+ }
+ time2 = System.currentTimeMillis();
+ duration = (time2 - time1) / (float) number;
+ System.out.println("Duration for r=" + number + " was " + duration + " ms/load.");
+ assertTrue("duration=" + duration, duration < 5);
+ }
+
+ System.out.println("\nMany instances.");
+ for (int number : range) {
+ time1 = System.currentTimeMillis();
+ for (int i = 0; i < number; i++) {
+ yaml = new Yaml(new Loader(new Constructor(Invoice.class)));
+ yaml.load(doc);
+ }
+ time2 = System.currentTimeMillis();
+ duration = (time2 - time1) / (float) number;
+ System.out.println("Duration for r=" + number + " was " + duration + " ms/load.");
+ assertTrue("duration=" + duration, duration < 5);
+ }
+ }
+} \ No newline at end of file
diff --git a/src/test/java/org/yaml/snakeyaml/Suit.java b/src/test/java/org/yaml/snakeyaml/Suit.java
new file mode 100644
index 00000000..9a409960
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/Suit.java
@@ -0,0 +1,8 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml;
+
+public enum Suit {
+ CLUBS, DIAMONDS, HEARTS, SPADES
+} \ No newline at end of file
diff --git a/src/test/java/org/yaml/snakeyaml/TypeDescriptionTest.java b/src/test/java/org/yaml/snakeyaml/TypeDescriptionTest.java
new file mode 100644
index 00000000..fe7d7be0
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/TypeDescriptionTest.java
@@ -0,0 +1,21 @@
+package org.yaml.snakeyaml;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.constructor.ArrayTagsTest.CarWithArray;
+
+public class TypeDescriptionTest extends TestCase {
+
+ public void testSetTag() {
+ TypeDescription descr = new TypeDescription(TypeDescriptionTest.class);
+ descr.setTag("!bla");
+ assertEquals("!bla", descr.getTag());
+ }
+
+ public void testToString() {
+ TypeDescription carDescription = new TypeDescription(CarWithArray.class, "!car");
+ assertEquals(
+ "TypeDescription for class org.yaml.snakeyaml.constructor.ArrayTagsTest$CarWithArray (tag='!car')",
+ carDescription.toString());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/Util.java b/src/test/java/org/yaml/snakeyaml/Util.java
new file mode 100644
index 00000000..2c87874a
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/Util.java
@@ -0,0 +1,39 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class Util {
+
+ public static String getLocalResource(String theName) throws IOException {
+ InputStream input;
+ input = YamlDocument.class.getClassLoader().getResourceAsStream(theName);
+ if (input == null) {
+ throw new RuntimeException("Can not find " + theName);
+ }
+ BufferedInputStream is = new BufferedInputStream(input);
+ StringBuffer buf = new StringBuffer(3000);
+ int i;
+ try {
+ while ((i = is.read()) != -1) {
+ buf.append((char) i);
+ }
+ } finally {
+ is.close();
+ }
+ String resource = buf.toString();
+ // convert EOLs
+ String[] lines = resource.split("\\r?\\n");
+ StringBuffer buffer = new StringBuffer();
+ for (int j = 0; j < lines.length; j++) {
+ buffer.append(lines[j]);
+ buffer.append("\n");
+ }
+ return buffer.toString();
+ }
+
+}
diff --git a/src/test/java/org/yaml/snakeyaml/YamlDocument.java b/src/test/java/org/yaml/snakeyaml/YamlDocument.java
new file mode 100644
index 00000000..1b5443e8
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/YamlDocument.java
@@ -0,0 +1,71 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStreamWriter;
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
+
+import org.yaml.snakeyaml.constructor.Constructor;
+
+public class YamlDocument {
+ public static final String ROOT = "specification/";
+ private String source;
+ private String presentation;
+ private Object nativeData;
+
+ public YamlDocument(String sourceName, boolean check, Constructor constructor) {
+ InputStream input = YamlDocument.class.getClassLoader().getResourceAsStream(
+ ROOT + sourceName);
+ if (constructor == null) {
+ constructor = new Constructor();
+ }
+ Loader loader = new Loader(constructor);
+ Yaml yaml = new Yaml(loader);
+ nativeData = yaml.load(input);
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+ Charset charset = Charset.forName("UTF-8");
+ yaml.dump(nativeData, new OutputStreamWriter(output, charset));
+ try {
+ presentation = output.toString(charset.name());
+ source = Util.getLocalResource(ROOT + sourceName);
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ // try to read generated presentation to prove that the presentation
+ // is identical to the source
+ Object result = yaml.load(presentation);
+ if (check && !nativeData.equals(result)) {
+ throw new RuntimeException("Generated presentation is not valid: " + presentation);
+ }
+ }
+
+ public YamlDocument(String sourceName, boolean check) {
+ this(sourceName, check, null);
+ }
+
+ public YamlDocument(String sourceName) {
+ this(sourceName, true);
+ }
+
+ public String getSource() {
+ return source;
+ }
+
+ public String getPresentation() {
+ return presentation;
+ }
+
+ public Object getNativeData() {
+ if (nativeData == null) {
+ throw new NullPointerException("No object is parsed.");
+ }
+ return nativeData;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/YamlStream.java b/src/test/java/org/yaml/snakeyaml/YamlStream.java
new file mode 100644
index 00000000..e4e9e099
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/YamlStream.java
@@ -0,0 +1,83 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml;
+
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.OutputStreamWriter;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.AssertionFailedError;
+
+public class YamlStream {
+ private List<Object> nativeData = new ArrayList<Object>();
+
+ @SuppressWarnings("unchecked")
+ public YamlStream(String sourceName) {
+ InputStream input = YamlDocument.class.getClassLoader().getResourceAsStream(
+ YamlDocument.ROOT + sourceName);
+ Yaml yaml = new Yaml();
+ for (Object document : yaml.loadAll(input)) {
+ nativeData.add(document);
+ }
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+ yaml.dumpAll(nativeData.iterator(), new OutputStreamWriter(output));
+ String presentation;
+ try {
+ presentation = output.toString("UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ // try to read generated presentation to prove that the presentation
+ // is identical to the source
+ List<Object> parsedNativeData = new ArrayList<Object>();
+ for (Object document : yaml.loadAll(presentation)) {
+ parsedNativeData.add(document);
+ }
+ if (nativeData.getClass() != parsedNativeData.getClass()) {
+ throw new AssertionFailedError("Different class: " + parsedNativeData.getClass());
+ }
+ if (nativeData.size() != parsedNativeData.size()) {
+ throw new AssertionFailedError("Different size.");
+ }
+ Iterator piterator = parsedNativeData.iterator();
+ Iterator niterator = nativeData.iterator();
+ while (piterator.hasNext()) {
+ Object obj1 = niterator.next();
+ Object obj2 = piterator.next();
+ if (obj1 instanceof Map) {
+ Map map1 = (Map) obj1;
+ Map map2 = (Map) obj2;
+ if (!map1.keySet().equals(map2.keySet())) {
+ throw new AssertionFailedError("Keyset: " + map1.keySet() + "; but was: "
+ + map2.keySet());
+ }
+ for (Iterator iterator = map1.keySet().iterator(); iterator.hasNext();) {
+ Object key = (Object) iterator.next();
+ Object o1 = map1.get(key);
+ Object o2 = map2.get(key);
+ if (!o1.equals(o2)) {
+ throw new AssertionFailedError("Values: " + o1 + "; but was: " + o2);
+ }
+ }
+ }
+ if (!obj1.equals(obj2)) {
+ throw new AssertionFailedError("Expected: " + obj1 + "; but was: " + obj2);
+ }
+ }
+ if (!parsedNativeData.equals(nativeData)) {
+ throw new AssertionFailedError("Generated presentation is not the same: "
+ + presentation);
+ }
+ }
+
+ public List<Object> getNativeData() {
+ return nativeData;
+ }
+
+}
diff --git a/src/test/java/org/yaml/snakeyaml/YamlTest.java b/src/test/java/org/yaml/snakeyaml/YamlTest.java
new file mode 100644
index 00000000..0041199e
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/YamlTest.java
@@ -0,0 +1,18 @@
+package org.yaml.snakeyaml;
+
+import junit.framework.TestCase;
+
+public class YamlTest extends TestCase {
+
+ public void testSetNoName() {
+ Yaml yaml = new Yaml();
+ assertTrue(yaml.toString().matches("Yaml:\\d+"));
+ }
+
+ public void testSetName() {
+ Yaml yaml = new Yaml();
+ yaml.setName("REST");
+ assertEquals("REST", yaml.getName());
+ assertEquals("REST", yaml.toString());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/composer/ComposerImplTest.java b/src/test/java/org/yaml/snakeyaml/composer/ComposerImplTest.java
new file mode 100644
index 00000000..5633c1ca
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/composer/ComposerImplTest.java
@@ -0,0 +1,37 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.composer;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.nodes.MappingNode;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.parser.Parser;
+import org.yaml.snakeyaml.parser.ParserImpl;
+import org.yaml.snakeyaml.reader.Reader;
+import org.yaml.snakeyaml.resolver.Resolver;
+
+public class ComposerImplTest extends TestCase {
+
+ public void testGetNode() {
+ String data = "american:\n - Boston Red Sox";
+ Node node = compose(data);
+ assertNotNull(node);
+ assertTrue(node instanceof MappingNode);
+ // System.out.println(node);
+ String data2 = "---\namerican:\n- Boston Red Sox";
+ Node node2 = compose(data2);
+ assertNotNull(node2);
+ assertFalse(node.equals(node2));
+ }
+
+ private Node compose(String data) {
+ Reader reader = new Reader(data);
+ Parser parser = new ParserImpl(reader);
+ Resolver resolver = new Resolver();
+ Composer composer = new Composer(parser, resolver);
+ Node node = composer.getSingleNode();
+ return node;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/constructor/ArrayTagsTest.java b/src/test/java/org/yaml/snakeyaml/constructor/ArrayTagsTest.java
new file mode 100644
index 00000000..5576b365
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/constructor/ArrayTagsTest.java
@@ -0,0 +1,89 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.constructor;
+
+import java.io.IOException;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Loader;
+import org.yaml.snakeyaml.TypeDescription;
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+
+public class ArrayTagsTest extends TestCase {
+
+ public void testDefaultRepresenter() throws IOException {
+ CarWithArray car = new CarWithArray();
+ car.setPlate("12-XP-F4");
+ Wheel[] wheels = new Wheel[5];
+ for (int i = 1; i < 6; i++) {
+ Wheel wheel = new Wheel();
+ wheel.setId(i);
+ wheels[i - 1] = wheel;
+ }
+ car.setWheels(wheels);
+ assertEquals(Util.getLocalResource("constructor/cararray-with-tags.yaml"), new Yaml()
+ .dump(car));
+ }
+
+ public void testLoadClassTag() throws IOException {
+ Constructor constructor = new Constructor();
+ constructor.addTypeDescription(new TypeDescription(Car.class, "!car"));
+ Loader loader = new Loader(constructor);
+ Yaml yaml = new Yaml(loader);
+ Car car = (Car) yaml.load(Util.getLocalResource("constructor/car-without-tags.yaml"));
+ assertEquals("12-XP-F4", car.getPlate());
+ List<Wheel> wheels = car.getWheels();
+ assertNotNull(wheels);
+ assertEquals(5, wheels.size());
+ }
+
+ public void testNullDescription() throws IOException {
+ Constructor constructor = new Constructor();
+ try {
+ constructor.addTypeDescription(null);
+ fail("Description is required.");
+ } catch (Exception e) {
+ assertEquals("TypeDescription is required.", e.getMessage());
+ }
+ }
+
+ public void testLoadClassNoRoot() throws IOException {
+ Constructor constructor = new Constructor();
+ TypeDescription carDescription = new TypeDescription(CarWithArray.class);
+ carDescription.setRoot(true);
+ constructor.addTypeDescription(carDescription);
+ Loader loader = new Loader(constructor);
+ Yaml yaml = new Yaml(loader);
+ CarWithArray car = (CarWithArray) yaml.load(Util
+ .getLocalResource("constructor/car-no-root-class.yaml"));
+ assertEquals("12-XP-F4", car.getPlate());
+ Wheel[] wheels = car.getWheels();
+ assertNotNull(wheels);
+ assertEquals(5, wheels.length);
+ }
+
+ public static class CarWithArray {
+ private String plate;
+ private Wheel[] wheels;
+
+ public String getPlate() {
+ return plate;
+ }
+
+ public void setPlate(String plate) {
+ this.plate = plate;
+ }
+
+ public Wheel[] getWheels() {
+ return wheels;
+ }
+
+ public void setWheels(Wheel[] wheels) {
+ this.wheels = wheels;
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/constructor/BeanConstructorTest.java b/src/test/java/org/yaml/snakeyaml/constructor/BeanConstructorTest.java
new file mode 100644
index 00000000..57d273c5
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/constructor/BeanConstructorTest.java
@@ -0,0 +1,228 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.constructor;
+
+import java.io.IOException;
+import java.math.BigInteger;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Loader;
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.error.YAMLException;
+
+public class BeanConstructorTest extends TestCase {
+
+ public void testPrimitivesConstructor() throws IOException {
+ Loader loader = new Loader(new Constructor(TestBean1.class));
+ Yaml yaml = new Yaml(loader);
+ String document = Util.getLocalResource("constructor/test-primitives1.yaml");
+ System.out.println(document);
+ TestBean1 result = (TestBean1) yaml.load(document);
+ assertNotNull(result);
+ assertEquals(new Byte((byte) 1), result.getByteClass());
+ assertEquals((byte) -3, result.getBytePrimitive());
+ assertEquals(new Short((short) 0), result.getShortClass());
+ assertEquals((short) -13, result.getShortPrimitive());
+ assertEquals(new Integer(5), result.getInteger());
+ assertEquals(17, result.getIntPrimitive());
+ assertEquals("the text", result.getText());
+ assertEquals("13", result.getId());
+ assertEquals(new Long(11111111111L), result.getLongClass());
+ assertEquals(9999999999L, result.getLongPrimitive());
+ assertEquals(Boolean.TRUE, result.getBooleanClass());
+ assertTrue(result.isBooleanPrimitive());
+ assertEquals(new Character('2'), result.getCharClass());
+ assertEquals('#', result.getCharPrimitive());
+ assertEquals(new BigInteger("1234567890123456789012345678901234567890"), result
+ .getBigInteger());
+ assertEquals(new Float(2), result.getFloatClass());
+ assertEquals(new Float(3.1416), result.getFloatPrimitive());
+ assertEquals(new Double(4), result.getDoubleClass());
+ assertEquals(new Double(11200), result.getDoublePrimitive());
+ assertEquals(1199836800000L, result.getDate().getTime());
+ assertEquals("public", result.publicField);
+ //
+ DumperOptions options = new DumperOptions();
+ options.setDefaultFlowStyle(DumperOptions.DefaultFlowStyle.BLOCK);
+ Yaml yamlToDump = new Yaml(options);
+ String output = yamlToDump.dump(result);
+ System.out.println(output);
+ TestBean1 result2 = (TestBean1) yaml.load(output);
+ assertNotNull(result2);
+ TestBean1 result3 = (TestBean1) new Yaml().load(output);
+ assertNotNull(result3);
+ }
+
+ public void testNoClassConstructor() {
+ try {
+ new Loader(new Constructor((Class<? extends Object>) null));
+ fail("Class must be provided.");
+ } catch (NullPointerException e) {
+ assertEquals("Root type must be provided.", e.getMessage());
+ }
+ }
+
+ public void testNoClassConstructorString() throws ClassNotFoundException {
+ try {
+ new Loader(new Constructor((String) null));
+ fail("Class must be provided.");
+ } catch (NullPointerException e) {
+ assertEquals("Root type must be provided.", e.getMessage());
+ }
+ }
+
+ public void testNoClassConstructorEmptyString() throws ClassNotFoundException {
+ try {
+ new Loader(new Constructor(" "));
+ fail("Class must be provided.");
+ } catch (YAMLException e) {
+ assertEquals("Root type must be provided.", e.getMessage());
+ }
+ }
+
+ public void testCharacter() throws IOException {
+ Loader loader = new Loader(new Constructor(TestBean1.class));
+ Yaml yaml = new Yaml(loader);
+ String document = "charClass: id";
+ try {
+ yaml.load(document);
+ fail("Only one char must be allowed.");
+ } catch (Exception e) {
+ assertTrue(e.getMessage(), e.getMessage().contains(
+ "Invalid node Character: 'id'; length: 2"));
+ }
+ document = "charClass: #";
+ try {
+ yaml.load(document);
+ fail("Only one char must be allowed.");
+ } catch (Exception e) {
+ assertTrue(e.getMessage(), e.getMessage().contains(
+ "Invalid node Character: ''; length: 0"));
+ }
+ document = "charClass: ''";
+ try {
+ yaml.load(document);
+ fail("Only one char must be allowed.");
+ } catch (Exception e) {
+ assertTrue(e.getMessage(), e.getMessage().contains(
+ "Invalid node Character: ''; length: 0"));
+ }
+ document = "charClass:\n";
+ try {
+ yaml.load(document);
+ fail("Only one char must be allowed.");
+ } catch (Exception e) {
+ assertTrue(e.getMessage(), e.getMessage().contains(
+ "Invalid node Character: ''; length: 0"));
+ }
+
+ }
+
+ public void testNoEmptyConstructor() throws IOException {
+ Loader loader = new Loader(new Constructor(TestBean2.class));
+ Yaml yaml = new Yaml(loader);
+ String document = "text: qwerty";
+ try {
+ yaml.load(document);
+ fail("No empty constructor available");
+ } catch (Exception e) {
+ assertTrue(e.getMessage(), e.getMessage().contains("InstantiationException"));
+ }
+ }
+
+ private class TestBean2 {
+ private String text;
+
+ public TestBean2(String text) {
+ this.text = text;
+ }
+
+ public String getText() {
+ return text;
+ }
+
+ public void setText(String text) {
+ this.text = text;
+ }
+ }
+
+ public void testPrivateMethod() throws IOException {
+ Loader loader = new Loader(new Constructor(TestBean3.class));
+ Yaml yaml = new Yaml(loader);
+ String document = "text: qwerty";
+ try {
+ yaml.load(document);
+ fail("Private method cannot be called.");
+ } catch (Exception e) {
+ assertTrue(e.getMessage(), e.getMessage().contains("InstantiationException"));
+ }
+ }
+
+ private class TestBean3 {
+ private String text;
+
+ public TestBean3() {
+ setText("123");
+ }
+
+ public String getText() {
+ return text;
+ }
+
+ private void setText(String text) {
+ this.text = text;
+ }
+ }
+
+ public void testKeyNotScalar() throws IOException {
+ Loader loader = new Loader(new Constructor(TestBean1.class));
+ Yaml yaml = new Yaml(loader);
+ String document = "[1, 2]: qwerty";
+ try {
+ yaml.load(document);
+ fail("Keys must be scalars.");
+ } catch (Exception e) {
+ assertTrue(e.getMessage(), e.getMessage().contains("Keys must be scalars but found"));
+ }
+ }
+
+ public void testInvalidKey() throws IOException {
+ Loader loader = new Loader(new Constructor(TestBean1.class));
+ Yaml yaml = new Yaml(loader);
+ String document = "something: qwerty";
+ try {
+ yaml.load(document);
+ fail("Non-existing property must fail.");
+ } catch (Exception e) {
+ assertTrue(e.getMessage(), e.getMessage().contains(
+ "Unable to find property 'something'"));
+ }
+ }
+
+ public void testStaticField() throws IOException {
+ Loader loader = new Loader(new Constructor(TestBean1.class));
+ Yaml yaml = new Yaml(loader);
+ String document = "staticInteger: 123";
+ try {
+ yaml.load(document);
+ fail("Staic variables must not be used.");
+ } catch (Exception e) {
+ assertTrue(e.getMessage(), e.getMessage().contains(
+ "Unable to find property 'staticInteger'"));
+ }
+ }
+
+ public void testScalarContructor() throws IOException {
+ Loader loader = new Loader(new Constructor(Parent1.class));
+ Yaml yaml = new Yaml(loader);
+ String document = "id: 123\nchild: 25";
+ Parent1 parent = (Parent1) yaml.load(document);
+ assertEquals("123", parent.getId());
+ Child1 child = parent.getChild();
+ assertEquals(new Integer(25), child.getCode());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/constructor/Car.java b/src/test/java/org/yaml/snakeyaml/constructor/Car.java
new file mode 100644
index 00000000..5e5b6f18
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/constructor/Car.java
@@ -0,0 +1,27 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.constructor;
+
+import java.util.List;
+
+public class Car {
+ private String plate;
+ private List<Wheel> wheels;
+
+ public String getPlate() {
+ return plate;
+ }
+
+ public void setPlate(String plate) {
+ this.plate = plate;
+ }
+
+ public List<Wheel> getWheels() {
+ return wheels;
+ }
+
+ public void setWheels(List<Wheel> wheels) {
+ this.wheels = wheels;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/constructor/Child1.java b/src/test/java/org/yaml/snakeyaml/constructor/Child1.java
new file mode 100644
index 00000000..eac79867
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/constructor/Child1.java
@@ -0,0 +1,16 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.constructor;
+
+public class Child1 {
+ private Integer code;
+
+ public Child1(Integer code) {
+ this.code = code;
+ }
+
+ public Integer getCode() {
+ return code;
+ }
+} \ No newline at end of file
diff --git a/src/test/java/org/yaml/snakeyaml/constructor/ClassTagsTest.java b/src/test/java/org/yaml/snakeyaml/constructor/ClassTagsTest.java
new file mode 100644
index 00000000..4bc80c0b
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/constructor/ClassTagsTest.java
@@ -0,0 +1,101 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.constructor;
+
+import java.io.IOException;
+import java.util.LinkedList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Dumper;
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Loader;
+import org.yaml.snakeyaml.TypeDescription;
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.error.YAMLException;
+import org.yaml.snakeyaml.representer.Representer;
+
+public class ClassTagsTest extends TestCase {
+
+ public void testDefaultRepresenter() throws IOException {
+ Car car = new Car();
+ car.setPlate("12-XP-F4");
+ List<Wheel> wheels = new LinkedList<Wheel>();
+ for (int i = 1; i < 6; i++) {
+ Wheel wheel = new Wheel();
+ wheel.setId(i);
+ wheels.add(wheel);
+ }
+ car.setWheels(wheels);
+ assertEquals(Util.getLocalResource("constructor/car-with-tags.yaml"), new Yaml().dump(car));
+ }
+
+ public void testDumpClassTag() throws IOException {
+ Car car = new Car();
+ car.setPlate("12-XP-F4");
+ List<Wheel> wheels = new LinkedList<Wheel>();
+ for (int i = 1; i < 6; i++) {
+ Wheel wheel = new Wheel();
+ wheel.setId(i);
+ wheels.add(wheel);
+ }
+ car.setWheels(wheels);
+ Representer representer = new Representer();
+ representer.addTypeDescription(new TypeDescription(Car.class, "!car"));
+ representer.addTypeDescription(new TypeDescription(Wheel.class, "tag:yaml.org,2002:map"));
+ Dumper dumper = new Dumper(representer, new DumperOptions());
+ Yaml yaml = new Yaml(dumper);
+ String output = yaml.dump(car);
+ assertEquals(Util.getLocalResource("constructor/car-without-tags.yaml"), output);
+ }
+
+ public void testLoadUnknounClassTag() throws IOException {
+ try {
+ Yaml yaml = new Yaml();
+ yaml.load(Util.getLocalResource("constructor/car-without-tags.yaml"));
+ fail("Must fail because of unknown tag: !car");
+ } catch (YAMLException e) {
+ assertTrue(e.getMessage().contains("Unknown tag: !car"));
+ }
+
+ }
+
+ public void testLoadClassTag() throws IOException {
+ Constructor constructor = new Constructor();
+ constructor.addTypeDescription(new TypeDescription(Car.class, "!car"));
+ Loader loader = new Loader(constructor);
+ Yaml yaml = new Yaml(loader);
+ Car car = (Car) yaml.load(Util.getLocalResource("constructor/car-without-tags.yaml"));
+ assertEquals("12-XP-F4", car.getPlate());
+ List<Wheel> wheels = car.getWheels();
+ assertNotNull(wheels);
+ assertEquals(5, wheels.size());
+ }
+
+ public void testNullDescription() throws IOException {
+ Constructor constructor = new Constructor();
+ try {
+ constructor.addTypeDescription(null);
+ fail("Description is required.");
+ } catch (Exception e) {
+ assertEquals("TypeDescription is required.", e.getMessage());
+ }
+ }
+
+ public void testLoadClassNoRoot() throws IOException {
+ Constructor constructor = new Constructor();
+ TypeDescription carDescription = new TypeDescription(Car.class);
+ carDescription.setRoot(true);
+ constructor.addTypeDescription(carDescription);
+ Loader loader = new Loader(constructor);
+ Yaml yaml = new Yaml(loader);
+ Car car = (Car) yaml.load(Util.getLocalResource("constructor/car-no-root-class.yaml"));
+ assertEquals("12-XP-F4", car.getPlate());
+ List<Wheel> wheels = car.getWheels();
+ assertNotNull(wheels);
+ assertEquals(5, wheels.size());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/constructor/ConstructorMappingTest.java b/src/test/java/org/yaml/snakeyaml/constructor/ConstructorMappingTest.java
new file mode 100644
index 00000000..3bdd6adb
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/constructor/ConstructorMappingTest.java
@@ -0,0 +1,55 @@
+package org.yaml.snakeyaml.constructor;
+
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.TreeMap;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.composer.Composer;
+import org.yaml.snakeyaml.parser.Parser;
+import org.yaml.snakeyaml.parser.ParserImpl;
+import org.yaml.snakeyaml.reader.Reader;
+import org.yaml.snakeyaml.resolver.Resolver;
+
+public class ConstructorMappingTest extends TestCase {
+
+ @SuppressWarnings("unchecked")
+ public void testGetDefaultMap() {
+ String data = "{ one: 1, two: 2, three: 3 }";
+ Map<Object, Object> map = (Map<Object, Object>) construct(new CustomConstructor(), data);
+ assertNotNull(map);
+ assertTrue(map.getClass().toString(), map instanceof TreeMap);
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testGetLinkedList() {
+ String data = "{ one: 1, two: 2, three: 3 }";
+ Map<Object, Object> map = (Map<Object, Object>) construct(data);
+ assertNotNull(map);
+ assertTrue(map.getClass().toString(), map instanceof LinkedHashMap);
+ }
+
+ private Object construct(String data) {
+ return construct(new Constructor(), data);
+ }
+
+ private Object construct(Constructor constructor, String data) {
+ Reader reader = new Reader(data);
+ Parser parser = new ParserImpl(reader);
+ Resolver resolver = new Resolver();
+ Composer composer = new Composer(parser, resolver);
+ constructor.setComposer(composer);
+ return constructor.getSingleData();
+ }
+
+ class CustomConstructor extends Constructor {
+ @Override
+ protected Map<Object, Object> createDefaultMap() {
+ return new TreeMap<Object, Object>();
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/constructor/ConstructorSequenceTest.java b/src/test/java/org/yaml/snakeyaml/constructor/ConstructorSequenceTest.java
new file mode 100644
index 00000000..5bc744a9
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/constructor/ConstructorSequenceTest.java
@@ -0,0 +1,74 @@
+package org.yaml.snakeyaml.constructor;
+
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.composer.Composer;
+import org.yaml.snakeyaml.parser.Parser;
+import org.yaml.snakeyaml.parser.ParserImpl;
+import org.yaml.snakeyaml.reader.Reader;
+import org.yaml.snakeyaml.resolver.Resolver;
+
+public class ConstructorSequenceTest extends TestCase {
+
+ public void testGetList() {
+ String data = "[ 1, 2, 3 ]";
+ List<Object> list = construct(new CustomConstructor(), data);
+ assertNotNull(list);
+ assertTrue(list.getClass().toString(), list instanceof ArrayList);
+ }
+
+ public void testGetLinkedList() {
+ String data = "[ 1, 2, 3 ]";
+ List<Object> list = construct(data);
+ assertNotNull(list);
+ assertTrue(list.getClass().toString(), list instanceof LinkedList);
+ }
+
+ public void testDumpList() {
+ List<Integer> l = new ArrayList<Integer>(2);
+ l.add(1);
+ l.add(2);
+ Yaml yaml = new Yaml();
+ String result = yaml.dump(l);
+ assertEquals("[1, 2]\n", result);
+ }
+
+ public void testDumpListSameIntegers() {
+ List<Integer> l = new ArrayList<Integer>(2);
+ l.add(1);
+ l.add(1);
+ Yaml yaml = new Yaml();
+ String result = yaml.dump(l);
+ assertEquals("[1, 1]\n", result);
+ }
+
+ private List<Object> construct(String data) {
+ return construct(new Constructor(), data);
+ }
+
+ @SuppressWarnings("unchecked")
+ private List<Object> construct(Constructor constructor, String data) {
+ Reader reader = new Reader(data);
+ Parser parser = new ParserImpl(reader);
+ Resolver resolver = new Resolver();
+ Composer composer = new Composer(parser, resolver);
+ constructor.setComposer(composer);
+ List result = (List) constructor.getSingleData();
+ return result;
+ }
+
+ class CustomConstructor extends Constructor {
+ @Override
+ protected List<Object> createDefaultList(int initSize) {
+ return new ArrayList<Object>(initSize);
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/constructor/ConstructorTest.java b/src/test/java/org/yaml/snakeyaml/constructor/ConstructorTest.java
new file mode 100644
index 00000000..9ee76be5
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/constructor/ConstructorTest.java
@@ -0,0 +1,89 @@
+package org.yaml.snakeyaml.constructor;
+
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.TimeZone;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+
+public class ConstructorTest extends TestCase {
+
+ @SuppressWarnings("unchecked")
+ public void testMapOrder() {
+ String data = "one: zzz\ntwo: ccc\nthree: bbb\nfour: aaa";
+ Object map = construct(data);
+ assertNotNull(map);
+ assertTrue(map.getClass().toString(), map instanceof LinkedHashMap);
+ Map<String, String> m = (Map<String, String>) map;
+ assertEquals(4, m.keySet().size());
+ Iterator<String> iter = m.keySet().iterator();
+ assertEquals("one", iter.next());
+ assertEquals("two", iter.next());
+ assertEquals("three", iter.next());
+ assertEquals("four", iter.next());
+ }
+
+ /**
+ * create JavaBean
+ */
+ public void testGetBeanAssumeClass() {
+ String data = "--- !!org.yaml.snakeyaml.constructor.Person\nfirstName: Andrey\nage: 99";
+ Object obj = construct(data);
+ assertNotNull(obj);
+ assertTrue("Unexpected: " + obj.getClass().toString(), obj instanceof Person);
+ Person person = (Person) obj;
+ assertEquals("Andrey", person.getFirstName());
+ assertNull(person.getLastName());
+ assertEquals(99, person.getAge().intValue());
+ }
+
+ /**
+ * create instance using constructor arguments
+ */
+ public void testGetConstructorBean() {
+ String data = "--- !!org.yaml.snakeyaml.constructor.Person [ Andrey, Somov, 99 ]";
+ Object obj = construct(data);
+ assertNotNull(obj);
+ assertTrue(obj.getClass().toString(), obj instanceof Person);
+ Person person = (Person) obj;
+ assertEquals("Andrey", person.getFirstName());
+ assertEquals("Somov", person.getLastName());
+ assertEquals(99, person.getAge().intValue());
+ }
+
+ /**
+ * create instance using scalar argument
+ */
+ public void testGetConstructorFromScalar() {
+ String data = "--- !!org.yaml.snakeyaml.constructor.Person 'Somov'";
+ Object obj = construct(data);
+ assertNotNull(obj);
+ assertTrue(obj.getClass().toString(), obj instanceof Person);
+ Person person = (Person) obj;
+ assertNull("Andrey", person.getFirstName());
+ assertEquals("Somov", person.getLastName());
+ assertNull(person.getAge());
+ }
+
+ public void testJavaBeanLoad() {
+ java.util.Calendar cal = java.util.Calendar.getInstance(TimeZone.getTimeZone("UTC"));
+ cal.clear();
+ cal.set(1982, 5 - 1, 3); // Java's months are zero-based...
+
+ TestBean expected = new TestBean("Ola Bini", 24, cal.getTime());
+ assertEquals(
+ expected,
+ construct("--- !!org.yaml.snakeyaml.constructor.TestBean\nname: Ola Bini\nage: 24\nborn: 1982-05-03\n"));
+ }
+
+ private Object construct(String data) {
+ Yaml yaml = new Yaml();
+ return yaml.load(data);
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/constructor/ImplicitTagsTest.java b/src/test/java/org/yaml/snakeyaml/constructor/ImplicitTagsTest.java
new file mode 100644
index 00000000..ade54ddc
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/constructor/ImplicitTagsTest.java
@@ -0,0 +1,149 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.constructor;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Dumper;
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Loader;
+import org.yaml.snakeyaml.TypeDescription;
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.representer.Representer;
+
+public class ImplicitTagsTest extends TestCase {
+
+ public void testDefaultRepresenter() throws IOException {
+ CarWithWheel car1 = new CarWithWheel();
+ car1.setPlate("12-XP-F4");
+ Wheel wheel = new Wheel();
+ wheel.setId(2);
+ car1.setWheel(wheel);
+ Map<String, Integer> map = new HashMap<String, Integer>();
+ map.put("id", 3);
+ car1.setMap(map);
+ car1.setPart(new Wheel(4));
+ car1.setYear("2008");
+ String carYaml1 = new Yaml().dump(car1);
+ assertEquals(Util.getLocalResource("constructor/carwheel-without-tags.yaml"), carYaml1);
+ CarWithWheel car2 = (CarWithWheel) new Yaml().load(carYaml1);
+ String carYaml2 = new Yaml().dump(car2);
+ assertEquals(carYaml1, carYaml2);
+ }
+
+ public void testNoRootTag() throws IOException {
+ CarWithWheel car1 = new CarWithWheel();
+ car1.setPlate("12-XP-F4");
+ Wheel wheel = new Wheel();
+ wheel.setId(2);
+ car1.setWheel(wheel);
+ Map<String, Integer> map = new HashMap<String, Integer>();
+ map.put("id", 3);
+ car1.setMap(map);
+ car1.setYear("2008");
+ DumperOptions options = new DumperOptions();
+ options.setExplicitRoot("tag:yaml.org,2002:map");
+ String carYaml1 = new Yaml(options).dump(car1);
+ assertEquals(Util.getLocalResource("constructor/car-without-root-tag.yaml"), carYaml1);
+ //
+ Constructor contructor = new Constructor(CarWithWheel.class);
+ Loader loader = new Loader(contructor);
+ CarWithWheel car2 = (CarWithWheel) new Yaml(loader).load(carYaml1);
+ String carYaml2 = new Yaml(options).dump(car2);
+ assertEquals(carYaml1, carYaml2);
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testRootMap() throws IOException {
+ Map<Object, Object> car1 = new HashMap<Object, Object>();
+ car1.put("plate", "12-XP-F4");
+ Wheel wheel = new Wheel();
+ wheel.setId(2);
+ car1.put("wheel", wheel);
+ Map<String, Integer> map = new HashMap<String, Integer>();
+ map.put("id", 3);
+ car1.put("map", map);
+ String carYaml1 = new Yaml().dump(car1);
+ assertEquals(Util.getLocalResource("constructor/carwheel-root-map.yaml"), carYaml1);
+ Map<Object, Object> car2 = (Map<Object, Object>) new Yaml().load(carYaml1);
+ assertEquals(car1, car2);
+ assertEquals(carYaml1, new Yaml().dump(car2));
+ }
+
+ public void testLoadClassTag() throws IOException {
+ Constructor constructor = new Constructor();
+ constructor.addTypeDescription(new TypeDescription(Car.class, "!car"));
+ Loader loader = new Loader(constructor);
+ Yaml yaml = new Yaml(loader);
+ Car car = (Car) yaml.load(Util.getLocalResource("constructor/car-without-tags.yaml"));
+ assertEquals("12-XP-F4", car.getPlate());
+ List<Wheel> wheels = car.getWheels();
+ assertNotNull(wheels);
+ assertEquals(5, wheels.size());
+ //
+ String carYaml1 = new Yaml().dump(car);
+ assertTrue(carYaml1.startsWith("!!org.yaml.snakeyaml.constructor.Car"));
+ //
+ Representer representer = new Representer();
+ representer.addTypeDescription(new TypeDescription(Car.class, "!car"));
+ Dumper dumper = new Dumper(representer, new DumperOptions());
+ yaml = new Yaml(dumper);
+ String carYaml2 = yaml.dump(car);
+ assertEquals(Util.getLocalResource("constructor/car-without-tags.yaml"), carYaml2);
+ }
+
+ public static class CarWithWheel {
+ private String plate;
+ private String year;
+ private Wheel wheel;
+ private Object part;
+ private Map<String, Integer> map;
+
+ public String getPlate() {
+ return plate;
+ }
+
+ public void setPlate(String plate) {
+ this.plate = plate;
+ }
+
+ public Wheel getWheel() {
+ return wheel;
+ }
+
+ public void setWheel(Wheel wheel) {
+ this.wheel = wheel;
+ }
+
+ public Map<String, Integer> getMap() {
+ return map;
+ }
+
+ public void setMap(Map<String, Integer> map) {
+ this.map = map;
+ }
+
+ public Object getPart() {
+ return part;
+ }
+
+ public void setPart(Object part) {
+ this.part = part;
+ }
+
+ public String getYear() {
+ return year;
+ }
+
+ public void setYear(String year) {
+ this.year = year;
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/constructor/MyCar.java b/src/test/java/org/yaml/snakeyaml/constructor/MyCar.java
new file mode 100644
index 00000000..c3107db1
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/constructor/MyCar.java
@@ -0,0 +1,37 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.constructor;
+
+import java.util.Date;
+import java.util.Map;
+
+public class MyCar {
+ private String plate;
+ private Map<MyWheel, Date> wheels;
+ private Map<String, Integer> windows;
+
+ public String getPlate() {
+ return plate;
+ }
+
+ public void setPlate(String plate) {
+ this.plate = plate;
+ }
+
+ public Map<MyWheel, Date> getWheels() {
+ return wheels;
+ }
+
+ public void setWheels(Map<MyWheel, Date> wheels) {
+ this.wheels = wheels;
+ }
+
+ public Map<String, Integer> getWindows() {
+ return windows;
+ }
+
+ public void setWindows(Map<String, Integer> windows) {
+ this.windows = windows;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/constructor/MyWheel.java b/src/test/java/org/yaml/snakeyaml/constructor/MyWheel.java
new file mode 100644
index 00000000..b99a8983
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/constructor/MyWheel.java
@@ -0,0 +1,49 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.constructor;
+
+public class MyWheel {
+ private int id;
+ private String brand;
+
+ public MyWheel() {
+ brand = "Pirelli";
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ @Override
+ public String toString() {
+ return "Wheel id=" + id;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof MyWheel) {
+ MyWheel wheel = (MyWheel) obj;
+ return id == wheel.getId();
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return new Integer(id).hashCode();
+ }
+
+ public String getBrand() {
+ return brand;
+ }
+
+ public void setBrand(String brand) {
+ this.brand = brand;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/constructor/Parent1.java b/src/test/java/org/yaml/snakeyaml/constructor/Parent1.java
new file mode 100644
index 00000000..c3652f3f
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/constructor/Parent1.java
@@ -0,0 +1,26 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.constructor;
+
+public class Parent1 {
+ private String id;
+ private Child1 child;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public Child1 getChild() {
+ return child;
+ }
+
+ public void setChild(Child1 child) {
+ this.child = child;
+ }
+
+} \ No newline at end of file
diff --git a/src/test/java/org/yaml/snakeyaml/constructor/Person.java b/src/test/java/org/yaml/snakeyaml/constructor/Person.java
new file mode 100644
index 00000000..0067f4b4
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/constructor/Person.java
@@ -0,0 +1,51 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.constructor;
+
+/**
+ * Test JavaBean
+ */
+public class Person {
+ private String firstName;
+ private String lastName;
+ private Integer age;
+
+ public Person(String firstName, String lastName, Integer age) {
+ this.firstName = firstName;
+ this.lastName = lastName;
+ this.age = age;
+ }
+
+ public Person() {
+ }
+
+ public Person(String lastName) {
+ this.lastName = lastName;
+ }
+
+ public String getFirstName() {
+ return firstName;
+ }
+
+ public void setFirstName(String firstName) {
+ this.firstName = firstName;
+ }
+
+ public String getLastName() {
+ return lastName;
+ }
+
+ public void setLastName(String lastName) {
+ this.lastName = lastName;
+ }
+
+ public Integer getAge() {
+ return age;
+ }
+
+ public void setAge(Integer age) {
+ this.age = age;
+ }
+
+}
diff --git a/src/test/java/org/yaml/snakeyaml/constructor/SafeConstructorTest.java b/src/test/java/org/yaml/snakeyaml/constructor/SafeConstructorTest.java
new file mode 100644
index 00000000..5b947a47
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/constructor/SafeConstructorTest.java
@@ -0,0 +1,39 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.constructor;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Loader;
+import org.yaml.snakeyaml.Yaml;
+
+public class SafeConstructorTest extends TestCase {
+
+ public void testConstructFloat() {
+ Yaml yaml = new Yaml();
+ assertEquals(3.1416, yaml.load("+3.1416"));
+ assertEquals(Double.POSITIVE_INFINITY, yaml.load("+.inf"));
+ assertEquals(Double.POSITIVE_INFINITY, yaml.load(".inf"));
+ assertEquals(Double.NEGATIVE_INFINITY, yaml.load("-.inf"));
+ }
+
+ public void testSafeConstruct() {
+ Yaml yaml = new Yaml(new Loader(new SafeConstructor()));
+ assertEquals(3.1416, yaml.load("+3.1416"));
+ }
+
+ public void testSafeConstructJavaBean() {
+ Yaml yaml = new Yaml(new Loader(new SafeConstructor()));
+ String data = "--- !!org.yaml.snakeyaml.constructor.Person\nfirstName: Andrey\nage: 99";
+ try {
+ yaml.load(data);
+ fail("JavaBeans cannot be created by SafeConstructor.");
+ } catch (ConstructorException e) {
+ assertTrue(e
+ .getMessage()
+ .contains(
+ "could not determine a constructor for the tag tag:yaml.org,2002:org.yaml.snakeyaml.constructor.Person"));
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/constructor/TestBean.java b/src/test/java/org/yaml/snakeyaml/constructor/TestBean.java
new file mode 100644
index 00000000..47ef11ca
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/constructor/TestBean.java
@@ -0,0 +1,71 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.constructor;
+
+import java.util.Date;
+
+/**
+ * @author <a href="mailto:ola.bini@ki.se">Ola Bini</a>
+ */
+public class TestBean {
+ private String name;
+ private int age;
+ private Date born;
+
+ public TestBean() {
+ }
+
+ public TestBean(final String name, final int age, final Date born) {
+ this.name = name;
+ this.age = age;
+ this.born = born;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ public int getAge() {
+ return age;
+ }
+
+ public Date getBorn() {
+ return born;
+ }
+
+ public void setName(final String name) {
+ this.name = name;
+ }
+
+ public void setAge(final int age) {
+ this.age = age;
+ }
+
+ public void setBorn(final Date born) {
+ this.born = born;
+ }
+
+ public boolean equals(final Object other) {
+ boolean ret = this == other;
+ if (!ret && other instanceof TestBean) {
+ TestBean o = (TestBean) other;
+ ret = this.name == null ? o.name == null : this.name.equals(o.name)
+ && this.age == o.age && this.born == null ? o.born == null : this.born
+ .equals(o.born);
+ }
+ return ret;
+ }
+
+ public int hashCode() {
+ int val = 3;
+ val += 3 * (name == null ? 0 : name.hashCode());
+ val += 3 * age;
+ val += 3 * (born == null ? 0 : born.hashCode());
+ return val;
+ }
+
+ public String toString() {
+ return "#<org.jvyaml.TestBean name=\"" + name + "\" age=" + age + " born=\"" + born + "\">";
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/constructor/TestBean1.java b/src/test/java/org/yaml/snakeyaml/constructor/TestBean1.java
new file mode 100644
index 00000000..18ef9e0c
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/constructor/TestBean1.java
@@ -0,0 +1,192 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.constructor;
+
+import java.math.BigInteger;
+import java.util.Date;
+
+public class TestBean1 {
+ private String text;
+ private String id;
+ private Byte byteClass;
+ private byte bytePrimitive;
+ private Short shortClass;
+ private short shortPrimitive;
+ private Integer integer;
+ private int intPrimitive;
+ private Long longClass;
+ private long longPrimitive;
+ private Boolean booleanClass;
+ private boolean booleanPrimitive;
+ private Character charClass;
+ private char charPrimitive;
+ private BigInteger bigInteger;
+ private Float floatClass;
+ private float floatPrimitive;
+ private Double doubleClass;
+ private double doublePrimitive;
+ private Date date;
+ public String publicField;
+ static public Integer staticInteger;
+
+ public String getText() {
+ return text;
+ }
+
+ public void setText(String text) {
+ this.text = text;
+ }
+
+ public Integer getInteger() {
+ return integer;
+ }
+
+ public void setInteger(Integer integer) {
+ this.integer = integer;
+ }
+
+ public int getIntPrimitive() {
+ return intPrimitive;
+ }
+
+ public void setIntPrimitive(int intPrimitive) {
+ this.intPrimitive = intPrimitive;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public Byte getByteClass() {
+ return byteClass;
+ }
+
+ public void setByteClass(Byte byteClass) {
+ this.byteClass = byteClass;
+ }
+
+ public byte getBytePrimitive() {
+ return bytePrimitive;
+ }
+
+ public void setBytePrimitive(byte bytePrimitive) {
+ this.bytePrimitive = bytePrimitive;
+ }
+
+ public Short getShortClass() {
+ return shortClass;
+ }
+
+ public void setShortClass(Short shortClass) {
+ this.shortClass = shortClass;
+ }
+
+ public short getShortPrimitive() {
+ return shortPrimitive;
+ }
+
+ public void setShortPrimitive(short shortPrimitive) {
+ this.shortPrimitive = shortPrimitive;
+ }
+
+ public Long getLongClass() {
+ return longClass;
+ }
+
+ public void setLongClass(Long longClass) {
+ this.longClass = longClass;
+ }
+
+ public long getLongPrimitive() {
+ return longPrimitive;
+ }
+
+ public void setLongPrimitive(long longPrimitive) {
+ this.longPrimitive = longPrimitive;
+ }
+
+ public Boolean getBooleanClass() {
+ return booleanClass;
+ }
+
+ public void setBooleanClass(Boolean booleanClass) {
+ this.booleanClass = booleanClass;
+ }
+
+ public boolean isBooleanPrimitive() {
+ return booleanPrimitive;
+ }
+
+ public void setBooleanPrimitive(boolean booleanPrimitive) {
+ this.booleanPrimitive = booleanPrimitive;
+ }
+
+ public Character getCharClass() {
+ return charClass;
+ }
+
+ public void setCharClass(Character charClass) {
+ this.charClass = charClass;
+ }
+
+ public char getCharPrimitive() {
+ return charPrimitive;
+ }
+
+ public void setCharPrimitive(char charPrimitive) {
+ this.charPrimitive = charPrimitive;
+ }
+
+ public BigInteger getBigInteger() {
+ return bigInteger;
+ }
+
+ public void setBigInteger(BigInteger bigInteger) {
+ this.bigInteger = bigInteger;
+ }
+
+ public Float getFloatClass() {
+ return floatClass;
+ }
+
+ public void setFloatClass(Float floatClass) {
+ this.floatClass = floatClass;
+ }
+
+ public float getFloatPrimitive() {
+ return floatPrimitive;
+ }
+
+ public void setFloatPrimitive(float floatPrimitive) {
+ this.floatPrimitive = floatPrimitive;
+ }
+
+ public Double getDoubleClass() {
+ return doubleClass;
+ }
+
+ public void setDoubleClass(Double doubleClass) {
+ this.doubleClass = doubleClass;
+ }
+
+ public double getDoublePrimitive() {
+ return doublePrimitive;
+ }
+
+ public void setDoublePrimitive(double doublePrimitive) {
+ this.doublePrimitive = doublePrimitive;
+ }
+
+ public Date getDate() {
+ return date;
+ }
+
+ public void setDate(Date date) {
+ this.date = date;
+ }
+} \ No newline at end of file
diff --git a/src/test/java/org/yaml/snakeyaml/constructor/TypeSafeCollectionsTest.java b/src/test/java/org/yaml/snakeyaml/constructor/TypeSafeCollectionsTest.java
new file mode 100644
index 00000000..3909325f
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/constructor/TypeSafeCollectionsTest.java
@@ -0,0 +1,82 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.constructor;
+
+import java.io.IOException;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Dumper;
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Loader;
+import org.yaml.snakeyaml.TypeDescription;
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.representer.Representer;
+
+public class TypeSafeCollectionsTest extends TestCase {
+
+ public void testTypeSafeList() throws IOException {
+ Constructor constructor = new Constructor(Car.class);
+ TypeDescription carDescription = new TypeDescription(Car.class);
+ carDescription.putListPropertyType("wheels", Wheel.class);
+ constructor.addTypeDescription(carDescription);
+ Loader loader = new Loader(constructor);
+ Yaml yaml = new Yaml(loader);
+ Car car = (Car) yaml.load(Util.getLocalResource("constructor/car-no-root-class.yaml"));
+ assertEquals("12-XP-F4", car.getPlate());
+ List<Wheel> wheels = car.getWheels();
+ assertNotNull(wheels);
+ assertEquals(5, wheels.size());
+ for (Wheel wheel : wheels) {
+ assertTrue(wheel.getId() > 0);
+ }
+ }
+
+ public void testTypeSafeMap() throws IOException {
+ Constructor constructor = new Constructor(MyCar.class);
+ TypeDescription carDescription = new TypeDescription(MyCar.class);
+ carDescription.putMapPropertyType("wheels", MyWheel.class, Object.class);
+ constructor.addTypeDescription(carDescription);
+ Loader loader = new Loader(constructor);
+ Yaml yaml = new Yaml(loader);
+ MyCar car = (MyCar) yaml.load(Util
+ .getLocalResource("constructor/car-no-root-class-map.yaml"));
+ assertEquals("00-FF-Q2", car.getPlate());
+ Map<MyWheel, Date> wheels = car.getWheels();
+ assertNotNull(wheels);
+ assertEquals(5, wheels.size());
+ for (MyWheel wheel : wheels.keySet()) {
+ assertTrue(wheel.getId() > 0);
+ Date date = wheels.get(wheel);
+ long time = date.getTime();
+ assertTrue("It must be midnight.", time % 10000 == 0);
+ }
+ }
+
+ public void test1() throws IOException {
+ Map<MyWheel, Date> wheels = new HashMap<MyWheel, Date>();
+ for (int i = 1; i < 6; i++) {
+ MyWheel mw = new MyWheel();
+ mw.setId(i);
+ if (i == 2) {
+ mw.setBrand("Michel");
+ }
+ wheels.put(mw, new Date());
+ }
+ MyCar c = new MyCar();
+ c.setPlate("00-FF-Q2");
+ c.setWheels(wheels);
+ Representer representer = new Representer();
+ representer.addTypeDescription(new TypeDescription(MyWheel.class, "tag:yaml.org,2002:map"));
+ Dumper dumper = new Dumper(representer, new DumperOptions());
+ Yaml yaml = new Yaml(dumper);
+ String output = yaml.dump(c);
+ System.out.println(output);
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/constructor/Wheel.java b/src/test/java/org/yaml/snakeyaml/constructor/Wheel.java
new file mode 100644
index 00000000..07e66f80
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/constructor/Wheel.java
@@ -0,0 +1,44 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.constructor;
+
+public class Wheel {
+ private int id;
+
+ public Wheel(int id) {
+ this.id = id;
+ }
+
+ public Wheel() {
+ this(0);
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ @Override
+ public String toString() {
+ return "Wheel id=" + id;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof Wheel) {
+ Wheel wheel = (Wheel) obj;
+ return id == wheel.getId();
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return new Integer(id).hashCode();
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/emitter/EmitterTest.java b/src/test/java/org/yaml/snakeyaml/emitter/EmitterTest.java
new file mode 100644
index 00000000..1314fbb9
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/emitter/EmitterTest.java
@@ -0,0 +1,82 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.emitter;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.DumperOptions.DefaultScalarStyle;
+
+public class EmitterTest extends TestCase {
+
+ public void testWriteFolded() {
+ DumperOptions options = new DumperOptions();
+ options.setDefaultStyle(DefaultScalarStyle.FOLDED);
+ String folded = "0123456789 0123456789\n0123456789 0123456789";
+ Map<String, String> map = new LinkedHashMap<String, String>();
+ map.put("aaa", folded);
+ map.put("bbb", "\nbla-bla\n");
+ Yaml yaml = new Yaml(options);
+ String output = yaml.dump(map);
+ String etalon = "\"aaa\": >-\n 0123456789 0123456789\n\n 0123456789 0123456789\n\"bbb\": >2\n\n bla-bla\n";
+ assertEquals(etalon, output);
+ }
+
+ public void testWriteLiteral() {
+ DumperOptions options = new DumperOptions();
+ options.setDefaultStyle(DefaultScalarStyle.LITERAL);
+ String folded = "0123456789 0123456789 0123456789 0123456789";
+ Map<String, String> map = new LinkedHashMap<String, String>();
+ map.put("aaa", folded);
+ map.put("bbb", "\nbla-bla\n");
+ Yaml yaml = new Yaml(options);
+ String output = yaml.dump(map);
+ System.out.println(output);
+ String etalon = "\"aaa\": |-\n 0123456789 0123456789 0123456789 0123456789\n\"bbb\": |2\n\n bla-bla\n";
+ assertEquals(etalon, output);
+ }
+
+ public void testWritePlain() {
+ DumperOptions options = new DumperOptions();
+ options.setDefaultStyle(DefaultScalarStyle.PLAIN);
+ String folded = "0123456789 0123456789\n0123456789 0123456789";
+ Map<String, String> map = new LinkedHashMap<String, String>();
+ map.put("aaa", folded);
+ map.put("bbb", "\nbla-bla");
+ Yaml yaml = new Yaml(options);
+ String output = yaml.dump(map);
+ String etalon = "{aaa: '0123456789 0123456789\n\n 0123456789 0123456789', bbb: '\n\n bla-bla'}\n";
+ assertEquals(etalon, output);
+ }
+
+ public void testWriteSingleQuoted() {
+ DumperOptions options = new DumperOptions();
+ options.setDefaultStyle(DefaultScalarStyle.SINGLE_QUOTED);
+ String folded = "0123456789 0123456789\n0123456789 0123456789";
+ Map<String, String> map = new LinkedHashMap<String, String>();
+ map.put("aaa", folded);
+ map.put("bbb", "\nbla-bla");
+ Yaml yaml = new Yaml(options);
+ String output = yaml.dump(map);
+ String etalon = "'aaa': '0123456789 0123456789\n\n 0123456789 0123456789'\n'bbb': '\n\n bla-bla'\n";
+ assertEquals(etalon, output);
+ }
+
+ public void testWriteDoubleQuoted() {
+ DumperOptions options = new DumperOptions();
+ options.setDefaultStyle(DefaultScalarStyle.DOUBLE_QUOTED);
+ String folded = "0123456789 0123456789\n0123456789 0123456789";
+ Map<String, String> map = new LinkedHashMap<String, String>();
+ map.put("aaa", folded);
+ map.put("bbb", "\nbla-bla");
+ Yaml yaml = new Yaml(options);
+ String output = yaml.dump(map);
+ String etalon = "\"aaa\": \"0123456789 0123456789\\n0123456789 0123456789\"\n\"bbb\": \"\\nbla-bla\"\n";
+ assertEquals(etalon, output);
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/emitter/EventConstructor.java b/src/test/java/org/yaml/snakeyaml/emitter/EventConstructor.java
new file mode 100644
index 00000000..7309e1ad
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/emitter/EventConstructor.java
@@ -0,0 +1,106 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.emitter;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.yaml.snakeyaml.constructor.Construct;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.events.AliasEvent;
+import org.yaml.snakeyaml.events.DocumentEndEvent;
+import org.yaml.snakeyaml.events.DocumentStartEvent;
+import org.yaml.snakeyaml.events.Event;
+import org.yaml.snakeyaml.events.MappingEndEvent;
+import org.yaml.snakeyaml.events.MappingStartEvent;
+import org.yaml.snakeyaml.events.ScalarEvent;
+import org.yaml.snakeyaml.events.SequenceEndEvent;
+import org.yaml.snakeyaml.events.SequenceStartEvent;
+import org.yaml.snakeyaml.events.StreamEndEvent;
+import org.yaml.snakeyaml.events.StreamStartEvent;
+import org.yaml.snakeyaml.nodes.MappingNode;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.ScalarNode;
+
+public class EventConstructor extends Constructor {
+
+ public EventConstructor() {
+ this.yamlConstructors.put(null, new ConstructEvent());
+ }
+
+ private class ConstructEvent implements Construct {
+
+ @SuppressWarnings("unchecked")
+ public Object construct(Node node) {
+ Map mapping;
+ if (node instanceof ScalarNode) {
+ mapping = new HashMap();
+ } else {
+ mapping = constructMapping((MappingNode) node);
+ }
+ String className = node.getTag().substring(1) + "Event";
+ Event value;
+ if (className.equals("AliasEvent")) {
+ value = new AliasEvent((String) mapping.get("anchor"), null, null);
+ } else if (className.equals("ScalarEvent")) {
+ String tag = (String) mapping.get("tag");
+ String v = (String) mapping.get("value");
+ if (v == null) {
+ v = "";
+ }
+ List implicitList = (List) mapping.get("implicit");
+ boolean implicit[];
+ if (implicitList == null) {
+ implicit = new boolean[] { false, true };
+ } else {
+ implicit = new boolean[2];
+ implicit[0] = (Boolean) implicitList.get(0);
+ implicit[1] = (Boolean) implicitList.get(1);
+ }
+ value = new ScalarEvent((String) mapping.get("anchor"), tag, implicit, v, null,
+ null, null);
+ } else if (className.equals("SequenceStartEvent")) {
+ String tag = (String) mapping.get("tag");
+ Boolean implicit = (Boolean) mapping.get("implicit");
+ if (implicit == null) {
+ implicit = true;
+ }
+ value = new SequenceStartEvent((String) mapping.get("anchor"), tag, implicit, null,
+ null, false);
+ } else if (className.equals("MappingStartEvent")) {
+ String tag = (String) mapping.get("tag");
+ Boolean implicit = (Boolean) mapping.get("implicit");
+ if (implicit == null) {
+ implicit = true;
+ }
+ value = new MappingStartEvent((String) mapping.get("anchor"), tag, implicit, null,
+ null, false);
+ } else if (className.equals("DocumentEndEvent")) {
+ value = new DocumentEndEvent(null, null, false);
+ } else if (className.equals("DocumentStartEvent")) {
+ Map<String, String> tags = (Map<String, String>) mapping.get("tags");
+ List<Integer> versionList = (List<Integer>) mapping.get("version");
+ Integer[] version = null;
+ if (versionList != null) {
+ version = new Integer[2];
+ version[0] = versionList.get(0).intValue();
+ version[1] = versionList.get(1).intValue();
+ }
+ value = new DocumentStartEvent(null, null, false, version, tags);
+ } else if (className.equals("MappingEndEvent")) {
+ value = new MappingEndEvent(null, null);
+ } else if (className.equals("SequenceEndEvent")) {
+ value = new SequenceEndEvent(null, null);
+ } else if (className.equals("StreamEndEvent")) {
+ value = new StreamEndEvent(null, null);
+ } else if (className.equals("StreamStartEvent")) {
+ value = new StreamStartEvent(null, null);
+ } else {
+ throw new UnsupportedOperationException();
+ }
+ return value;
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/emitter/EventsLoader.java b/src/test/java/org/yaml/snakeyaml/emitter/EventsLoader.java
new file mode 100644
index 00000000..567f5290
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/emitter/EventsLoader.java
@@ -0,0 +1,13 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.emitter;
+
+import org.yaml.snakeyaml.Loader;
+
+public class EventsLoader extends Loader {
+
+ public EventsLoader() {
+ super(new EventConstructor());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/error/MarkTest.java b/src/test/java/org/yaml/snakeyaml/error/MarkTest.java
new file mode 100644
index 00000000..40a88a74
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/error/MarkTest.java
@@ -0,0 +1,25 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.error;
+
+import junit.framework.TestCase;
+
+public class MarkTest extends TestCase {
+
+ public void testGet_snippet() {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ assertEquals(" *The first line.\n ^", mark.get_snippet());
+ mark = new Mark("test1", 9, 0, 0, "The first*line.\nThe last line.", 9);
+ assertEquals(" The first*line.\n ^", mark.get_snippet());
+ }
+
+ public void testToString() {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ String[] lines = mark.toString().split("\n");
+ assertEquals(" in \"test1\", line 0, column 0:", lines[0]);
+ assertEquals("*The first line.", lines[1].trim());
+ assertEquals("^", lines[2].trim());
+ }
+
+}
diff --git a/src/test/java/org/yaml/snakeyaml/error/MarkedYAMLExceptionTest.java b/src/test/java/org/yaml/snakeyaml/error/MarkedYAMLExceptionTest.java
new file mode 100644
index 00000000..dc6991cb
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/error/MarkedYAMLExceptionTest.java
@@ -0,0 +1,27 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.error;
+
+import junit.framework.TestCase;
+
+public class MarkedYAMLExceptionTest extends TestCase {
+
+ public void testToString1() {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ MarkedYAMLException exception = new MarkedYAMLException(null, null, "Error happened", mark);
+ assertTrue(exception.toString().contains("Error happened"));
+ assertTrue(exception.toString().contains("The first line"));
+ assertTrue(exception.toString().contains("\"test1\""));
+ }
+
+ public void testToString2() {
+ Mark mark = new Mark("search", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ MarkedYAMLException exception = new MarkedYAMLException("See http://www.google.com", mark,
+ "Error2 happened", mark);
+ assertTrue(exception.toString().contains("Error2 happened"));
+ assertTrue(exception.toString().contains("The first line"));
+ assertTrue(exception.toString().contains("\"search\""));
+ }
+
+}
diff --git a/src/test/java/org/yaml/snakeyaml/events/ScalarEventTest.java b/src/test/java/org/yaml/snakeyaml/events/ScalarEventTest.java
new file mode 100644
index 00000000..2406ce03
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/events/ScalarEventTest.java
@@ -0,0 +1,27 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.events;
+
+import junit.framework.TestCase;
+
+public class ScalarEventTest extends TestCase {
+
+ public void testToString() {
+ boolean[] implicit = new boolean[2];
+ implicit[0] = true;
+ implicit[1] = true;
+ ScalarEvent event = new ScalarEvent("a2", "str", implicit, "text", null, null, '"');
+ assertEquals(
+ "<org.yaml.snakeyaml.events.ScalarEvent(anchor=a2, tag=str, implicit=[true, true], value=text)>",
+ event.toString());
+ }
+
+ public void testNotEqual() {
+ boolean[] implicit = new boolean[2];
+ implicit[0] = true;
+ implicit[1] = true;
+ ScalarEvent event = new ScalarEvent("a2", "str", implicit, "text", null, null, '"');
+ assertFalse(event.equals(event.toString()));
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/introspector/MethodPropertyTest.java b/src/test/java/org/yaml/snakeyaml/introspector/MethodPropertyTest.java
new file mode 100644
index 00000000..1bcb7dcf
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/introspector/MethodPropertyTest.java
@@ -0,0 +1,22 @@
+package org.yaml.snakeyaml.introspector;
+
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.constructor.TestBean1;
+
+public class MethodPropertyTest extends TestCase {
+
+ public void testToString() throws IntrospectionException {
+ for (PropertyDescriptor property : Introspector.getBeanInfo(TestBean1.class)
+ .getPropertyDescriptors()) {
+ if (property.getName().equals("text")) {
+ MethodProperty prop = new MethodProperty(property);
+ assertEquals("text of class java.lang.String", prop.toString());
+ }
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/nodes/NodeTest.java b/src/test/java/org/yaml/snakeyaml/nodes/NodeTest.java
new file mode 100644
index 00000000..eb9d817c
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/nodes/NodeTest.java
@@ -0,0 +1,28 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.nodes;
+
+import junit.framework.TestCase;
+
+public class NodeTest extends TestCase {
+
+ public void testNode() {
+ try {
+ new ScalarNode("!foo", null, null, null, '"');
+ fail("Value must be required.");
+ } catch (Exception e) {
+ assertEquals("value in a Node is required.", e.getMessage());
+ }
+ }
+
+ public void testSetTag() {
+ try {
+ ScalarNode node = new ScalarNode("!foo", "Value1", null, null, '"');
+ node.setTag(null);
+ fail("Value must be required.");
+ } catch (Exception e) {
+ assertEquals("tag in a Node is required.", e.getMessage());
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/nodes/ScalarNodeTest.java b/src/test/java/org/yaml/snakeyaml/nodes/ScalarNodeTest.java
new file mode 100644
index 00000000..c5eb45df
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/nodes/ScalarNodeTest.java
@@ -0,0 +1,26 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.nodes;
+
+import junit.framework.TestCase;
+
+public class ScalarNodeTest extends TestCase {
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ public void testGetNodeId() {
+ Node node = new ScalarNode("str", "text", null, null, '>');
+ assertEquals(NodeId.scalar, node.getNodeId());
+ }
+
+ public void testToString() {
+ Node node = new ScalarNode("str", "text", null, null, '>');
+ assertTrue(node.toString().contains("ScalarNode"));
+ assertTrue(node.toString().contains("tag="));
+ assertTrue(node.toString().contains("value="));
+ }
+
+}
diff --git a/src/test/java/org/yaml/snakeyaml/nodes/SequenceNodeTest.java b/src/test/java/org/yaml/snakeyaml/nodes/SequenceNodeTest.java
new file mode 100644
index 00000000..d8a08afb
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/nodes/SequenceNodeTest.java
@@ -0,0 +1,16 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.nodes;
+
+import java.util.ArrayList;
+
+import junit.framework.TestCase;
+
+public class SequenceNodeTest extends TestCase {
+
+ public void testGetNodeId() {
+ SequenceNode node = new SequenceNode("!foo", new ArrayList<Node>(), null, null, true);
+ assertEquals(NodeId.sequence, node.getNodeId());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/parser/ParserImplTest.java b/src/test/java/org/yaml/snakeyaml/parser/ParserImplTest.java
new file mode 100644
index 00000000..9e3f624c
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/parser/ParserImplTest.java
@@ -0,0 +1,88 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.parser;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.error.Mark;
+import org.yaml.snakeyaml.events.DocumentEndEvent;
+import org.yaml.snakeyaml.events.DocumentStartEvent;
+import org.yaml.snakeyaml.events.Event;
+import org.yaml.snakeyaml.events.MappingEndEvent;
+import org.yaml.snakeyaml.events.MappingStartEvent;
+import org.yaml.snakeyaml.events.ScalarEvent;
+import org.yaml.snakeyaml.events.SequenceEndEvent;
+import org.yaml.snakeyaml.events.SequenceStartEvent;
+import org.yaml.snakeyaml.events.StreamEndEvent;
+import org.yaml.snakeyaml.events.StreamStartEvent;
+import org.yaml.snakeyaml.reader.Reader;
+
+public class ParserImplTest extends TestCase {
+
+ public void testGetEvent() {
+ String data = "string: abcd";
+ Reader reader = new Reader(data);
+ Parser parser = new ParserImpl(reader);
+ Mark dummyMark = new Mark("dummy", 0, 0, 0, "", 0);
+ LinkedList<Event> etalonEvents = new LinkedList<Event>();
+ etalonEvents.add(new StreamStartEvent(dummyMark, dummyMark));
+ etalonEvents.add(new DocumentStartEvent(dummyMark, dummyMark, false, null, null));
+ etalonEvents.add(new MappingStartEvent(null, null, true, dummyMark, dummyMark,
+ Boolean.FALSE));
+ boolean[] implicit = { true, false };
+ etalonEvents.add(new ScalarEvent(null, null, implicit, "string", dummyMark, dummyMark,
+ (char) 0));
+ etalonEvents.add(new ScalarEvent(null, null, implicit, "abcd", dummyMark, dummyMark,
+ (char) 0));
+ etalonEvents.add(new MappingEndEvent(dummyMark, dummyMark));
+ etalonEvents.add(new DocumentEndEvent(dummyMark, dummyMark, false));
+ etalonEvents.add(new StreamEndEvent(dummyMark, dummyMark));
+ while (parser.checkEvent(new ArrayList<Class<? extends Event>>())) {
+ Event event = parser.getEvent();
+ if (etalonEvents.isEmpty()) {
+ fail("unexpected event: " + event);
+ }
+ assertEquals(etalonEvents.removeFirst(), event);
+ // System.out.println(event);
+ }
+ assertFalse("Must contain no more events: " + parser.getEvent(), parser
+ .checkEvent(new ArrayList<Class<? extends Event>>()));
+ }
+
+ public void testGetEvent2() {
+ String data = "american:\n - Boston Red Sox";
+ Reader reader = new Reader(data);
+ Parser parser = new ParserImpl(reader);
+ Mark dummyMark = new Mark("dummy", 0, 0, 0, "", 0);
+ LinkedList<Event> etalonEvents = new LinkedList<Event>();
+ etalonEvents.add(new StreamStartEvent(dummyMark, dummyMark));
+ etalonEvents.add(new DocumentStartEvent(dummyMark, dummyMark, false, null, null));
+ etalonEvents
+ .add(new MappingStartEvent(null, null, true, dummyMark, dummyMark, Boolean.TRUE));
+ boolean[] implicit = { true, false };
+ etalonEvents.add(new ScalarEvent(null, null, implicit, "american", dummyMark, dummyMark,
+ (char) 0));
+ etalonEvents.add(new SequenceStartEvent(null, null, true, dummyMark, dummyMark,
+ Boolean.FALSE));
+ etalonEvents.add(new ScalarEvent(null, null, implicit, "Boston Red Sox", dummyMark,
+ dummyMark, (char) 0));
+ etalonEvents.add(new SequenceEndEvent(dummyMark, dummyMark));
+ etalonEvents.add(new MappingEndEvent(dummyMark, dummyMark));
+ etalonEvents.add(new DocumentEndEvent(dummyMark, dummyMark, false));
+ etalonEvents.add(new StreamEndEvent(dummyMark, dummyMark));
+ while (parser.checkEvent(new ArrayList<Class<? extends Event>>())) {
+ Event event = parser.getEvent();
+ if (etalonEvents.isEmpty()) {
+ fail("unexpected event: " + event);
+ }
+ assertEquals(etalonEvents.removeFirst(), event);
+ // System.out.println(event);
+ }
+ assertFalse("Must contain no more events: " + parser.getEvent(), parser
+ .checkEvent(new ArrayList<Class<? extends Event>>()));
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/reader/IoReaderTest.java b/src/test/java/org/yaml/snakeyaml/reader/IoReaderTest.java
new file mode 100644
index 00000000..8a69beec
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/reader/IoReaderTest.java
@@ -0,0 +1,25 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.reader;
+
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+
+public class IoReaderTest extends TestCase {
+
+ @SuppressWarnings("unchecked")
+ public void testCheckPrintable() throws IOException {
+ Yaml yaml = new Yaml();
+ java.io.Reader reader = null;
+ reader = new FileReader("src/test/resources/specification/example2_1.yaml");
+ List<String> list = (List<String>) yaml.load(reader);
+ reader.close();
+ assertEquals(3, list.size());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/reader/ReaderBomTest.java b/src/test/java/org/yaml/snakeyaml/reader/ReaderBomTest.java
new file mode 100644
index 00000000..b5d6578c
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/reader/ReaderBomTest.java
@@ -0,0 +1,101 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.reader;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringReader;
+import java.nio.charset.Charset;
+
+import junit.framework.TestCase;
+
+public class ReaderBomTest extends TestCase {
+
+ public void testReader() throws IOException {
+ java.io.Reader input = new StringReader("test");
+ Reader reader = new Reader(input);
+ assertEquals('t', reader.peek());
+ reader.forward(1);
+ assertEquals('e', reader.peek());
+ reader.forward(1);
+ assertEquals('s', reader.peek());
+ reader.forward(1);
+ assertEquals('t', reader.peek());
+ reader.forward(1);
+ assertEquals('\u0000', reader.peek());
+ }
+
+ public void testNoBom() throws IOException {
+ byte[] data = "test".getBytes("UTF-8");
+ ByteArrayInputStream input = new ByteArrayInputStream(data);
+ java.io.Reader r = new UnicodeReader(input);
+ Reader reader = new Reader(r);
+ assertEquals('t', reader.peek());
+ assertEquals(Charset.forName("UTF-8"), reader.getEncoding());
+ reader.forward(1);
+ assertEquals('e', reader.peek());
+ reader.forward(1);
+ assertEquals('s', reader.peek());
+ reader.forward(1);
+ assertEquals('t', reader.peek());
+ reader.forward(1);
+ assertEquals('\u0000', reader.peek());
+ r.close();
+ }
+
+ public void testUtf8Bom() throws IOException {
+ File file = new File("src/test/resources/reader/utf-8.txt");
+ assertTrue("Test file not found: " + file.getAbsolutePath(), file.exists());
+ InputStream input = new FileInputStream(file);
+ Reader reader = new Reader(new UnicodeReader(input));
+ assertEquals('t', reader.peek());
+ reader.forward(1);
+ assertEquals('e', reader.peek());
+ reader.forward(1);
+ assertEquals('s', reader.peek());
+ reader.forward(1);
+ assertEquals('t', reader.peek());
+ reader.forward(1);
+ assertEquals('\u0000', reader.peek());
+ assertEquals(Charset.forName("UTF-8"), reader.getEncoding());
+ }
+
+ public void testUnicodeLeBom() throws IOException {
+ File file = new File("src/test/resources/reader/unicode-16le.txt");
+ assertTrue("Test file not found: " + file.getAbsolutePath(), file.exists());
+ InputStream input = new FileInputStream(file);
+ Reader reader = new Reader(new UnicodeReader(input));
+ assertEquals('t', reader.peek());
+ reader.forward(1);
+ assertEquals('e', reader.peek());
+ reader.forward(1);
+ assertEquals('s', reader.peek());
+ reader.forward(1);
+ assertEquals('t', reader.peek());
+ reader.forward(1);
+ assertEquals('\u0000', reader.peek());
+ assertEquals(Charset.forName("UTF-16LE"), reader.getEncoding());
+ }
+
+ public void testUnicodeBeBom() throws IOException {
+ File file = new File("src/test/resources/reader/unicode-16be.txt");
+ assertTrue("Test file not found: " + file.getAbsolutePath(), file.exists());
+ InputStream input = new FileInputStream(file);
+ Reader reader = new Reader(new UnicodeReader(input));
+ assertEquals('t', reader.peek());
+ reader.forward(1);
+ assertEquals('e', reader.peek());
+ reader.forward(1);
+ assertEquals('s', reader.peek());
+ reader.forward(1);
+ assertEquals('t', reader.peek());
+ reader.forward(1);
+ assertEquals('\u0000', reader.peek());
+ assertEquals(Charset.forName("UTF-16BE"), reader.getEncoding());
+ }
+
+}
diff --git a/src/test/java/org/yaml/snakeyaml/reader/ReaderStringTest.java b/src/test/java/org/yaml/snakeyaml/reader/ReaderStringTest.java
new file mode 100644
index 00000000..d4a98f8a
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/reader/ReaderStringTest.java
@@ -0,0 +1,61 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.reader;
+
+import java.util.regex.Matcher;
+
+import junit.framework.TestCase;
+
+public class ReaderStringTest extends TestCase {
+
+ public void testCheckPrintable() {
+ Reader reader = new Reader("test");
+ reader.checkPrintable("test");
+ Matcher matcher = Reader.NON_PRINTABLE.matcher("test");
+ assertFalse(matcher.find());
+ }
+
+ public void testCheckNonPrintable() {
+ Matcher matcher = Reader.NON_PRINTABLE.matcher("test\u0005 fail");
+ assertTrue(matcher.find());
+ try {
+ new Reader("test\u0005 fail");
+ fail("Non printable Unicode characters must not be accepted.");
+ } catch (ReaderException e) {
+ assertEquals(
+ "unacceptable character #5 special characters are not allowed\nin \"<string>\", position 4",
+ e.toString());
+ }
+ }
+
+ public void testForward() {
+ Reader reader = new Reader("test");
+ while (reader.peek() != '\u0000') {
+ reader.forward(1);
+ }
+ reader = new Reader("test");
+ assertEquals('t', reader.peek());
+ reader.forward(1);
+ assertEquals('e', reader.peek());
+ reader.forward(1);
+ assertEquals('s', reader.peek());
+ reader.forward(1);
+ assertEquals('t', reader.peek());
+ reader.forward(1);
+ assertEquals('\u0000', reader.peek());
+ }
+
+ public void testPeekInt() {
+ Reader reader = new Reader("test");
+ assertEquals('t', reader.peek(0));
+ assertEquals('e', reader.peek(1));
+ assertEquals('s', reader.peek(2));
+ assertEquals('t', reader.peek(3));
+ reader.forward(1);
+ assertEquals('e', reader.peek(0));
+ assertEquals('s', reader.peek(1));
+ assertEquals('t', reader.peek(2));
+ }
+
+}
diff --git a/src/test/java/org/yaml/snakeyaml/representer/RepresentTest.java b/src/test/java/org/yaml/snakeyaml/representer/RepresentTest.java
new file mode 100644
index 00000000..89f1c386
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/representer/RepresentTest.java
@@ -0,0 +1,83 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.representer;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Dumper;
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Loader;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.Construct;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.ScalarNode;
+
+public class RepresentTest extends TestCase {
+
+ public void testCustomRepresenter() {
+ Dumper dumper = new Dumper(new MyRepresenter(), new DumperOptions());
+ Loader loader = new Loader(new MyConstructor());
+ Yaml yaml = new Yaml(loader, dumper);
+ CustomBean etalon = new CustomBean("A", 1);
+ String output = yaml.dump(etalon);
+ assertEquals("!!Dice 'Ad1'\n", output);
+ CustomBean bean = (CustomBean) yaml.load(output);
+ assertEquals("A", bean.getPrefix());
+ assertEquals(1, bean.getSuffix());
+ assertEquals(etalon, bean);
+ }
+
+ class CustomBean {
+ private String prefix;
+ private int suffix;
+
+ public CustomBean(String prefix, int suffix) {
+ this.prefix = prefix;
+ this.suffix = suffix;
+ }
+
+ public String getPrefix() {
+ return prefix;
+ }
+
+ public int getSuffix() {
+ return suffix;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ CustomBean bean = (CustomBean) obj;
+ return prefix.equals(bean.getPrefix()) && suffix == bean.getSuffix();
+ }
+ }
+
+ class MyRepresenter extends Representer {
+ public MyRepresenter() {
+ this.representers.put(CustomBean.class, new RepresentDice());
+ }
+
+ private class RepresentDice implements Represent {
+ public Node representData(Object data) {
+ CustomBean coin = (CustomBean) data;
+ String value = coin.getPrefix() + "d" + coin.getSuffix();
+ return representScalar("!!Dice", value);
+ }
+ }
+ }
+
+ class MyConstructor extends Constructor {
+
+ public MyConstructor() {
+ this.yamlConstructors.put("tag:yaml.org,2002:Dice", new ConstuctDice());
+ }
+
+ private class ConstuctDice implements Construct {
+ public Object construct(Node node) {
+ String val = (String) constructScalar((ScalarNode) node);
+ return new CustomBean(val.substring(0, 1), Integer.parseInt(val.substring(2)));
+ }
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/representer/RepresenterTest.java b/src/test/java/org/yaml/snakeyaml/representer/RepresenterTest.java
new file mode 100644
index 00000000..af050360
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/representer/RepresenterTest.java
@@ -0,0 +1,131 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.representer;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+
+public class RepresenterTest extends TestCase {
+
+ public void testRepresenter() {
+ MyBean bean = new MyBean();
+ bean.setName("Gnome");
+ bean.setValid(true);
+ bean.setPrimitive(true);
+ Yaml yaml = new Yaml();
+ assertEquals(
+ "!!org.yaml.snakeyaml.representer.RepresenterTest$MyBean {name: Gnome, primitive: true}\n",
+ yaml.dump(bean));
+ }
+
+ public static class MyBean {
+ private String name;
+ private Boolean valid;
+ private boolean primitive;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Boolean isValid() {
+ return valid;
+ }
+
+ public void setValid(Boolean valid) {
+ this.valid = valid;
+ }
+
+ public boolean isPrimitive() {
+ return primitive;
+ }
+
+ public void setPrimitive(boolean primitive) {
+ this.primitive = primitive;
+ }
+ }
+
+ public void testRepresenterNoConstructorAvailable() {
+ MyBean2 bean = new MyBean2("Gnome", true);
+ Yaml yaml = new Yaml();
+ assertEquals("!!org.yaml.snakeyaml.representer.RepresenterTest$MyBean2 {valid: true}\n",
+ yaml.dump(bean));
+ }
+
+ public static class MyBean2 {
+ private String name;
+ private Boolean valid;
+
+ public MyBean2(String name, Boolean valid) {
+ this();
+ this.name = name;
+ this.valid = valid;
+ }
+
+ private MyBean2() {
+ super();
+ }
+
+ private String getName() {
+ return name;
+ }
+
+ public Boolean getValid() {
+ return valid;
+ }
+
+ @Override
+ public String toString() {
+ return getName() + " " + getValid();
+ }
+ }
+
+ public void testRepresenterGetterWithException() {
+ MyBean3 bean = new MyBean3("Gnome", true);
+ Yaml yaml = new Yaml();
+ try {
+ yaml.dump(bean);
+ fail("Exception must be reported");
+ } catch (Exception e) {
+ assertTrue(true);
+ }
+ }
+
+ public static class MyBean3 {
+ private String name;
+ private Boolean valid;
+
+ public MyBean3(String name, Boolean valid) {
+ this.name = name;
+ this.valid = valid;
+ }
+
+ public String getName() {
+ throw new UnsupportedOperationException("Test.");
+ }
+
+ public Boolean isValid() {
+ return valid;
+ }
+
+ @Override
+ public String toString() {
+ return name + " " + isValid();
+ }
+ }
+
+ public void testRepresenterAddNull() {
+ Representer representer = new Representer();
+ try {
+ representer.addTypeDescription(null);
+ fail("Representer must be provided.");
+ } catch (Exception e) {
+ assertTrue(true);
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/representer/SafeRepresenterTest.java b/src/test/java/org/yaml/snakeyaml/representer/SafeRepresenterTest.java
new file mode 100644
index 00000000..262161a7
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/representer/SafeRepresenterTest.java
@@ -0,0 +1,105 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.representer;
+
+import java.math.BigInteger;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Yaml;
+
+public class SafeRepresenterTest extends TestCase {
+
+ public void testBinaryPattern() {
+ Pattern pattern = SafeRepresenter.BINARY_PATTERN;
+ assertFalse(pattern.matcher("\tAndrey\r\n").find());
+ assertTrue(pattern.matcher("\u0005Andrey").find());
+ }
+
+ public void testFloat() {
+ assertEquals("1.0E12", new Double("1e12").toString());
+ }
+
+ public void testNumber() {
+ List<Number> list = new LinkedList<Number>();
+ list.add(new Byte((byte) 3));
+ list.add(new Short((short) 4));
+ list.add(new Integer(5));
+ list.add(new BigInteger("6"));
+ list.add(new Long(7L));
+ list.add(Double.POSITIVE_INFINITY);
+ list.add(Double.NEGATIVE_INFINITY);
+ list.add(Double.NaN);
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(list);
+ assertEquals("[3, 4, 5, 6, 7, .inf, -.inf, .NaN]\n", output);
+ }
+
+ public void testDate() {
+ List<Date> list = new LinkedList<Date>();
+ list.add(new Date(1229684761159L));
+ list.add(new Date(1229684761059L));
+ list.add(new Date(1229684761009L));
+ list.add(new Date(1229684761150L));
+ list.add(new Date(1229684761100L));
+ list.add(new Date(1229684761000L));
+ list.add(new Date(1229684760000L));
+ DumperOptions options = new DumperOptions();
+ options.setDefaultFlowStyle(DumperOptions.DefaultFlowStyle.BLOCK);
+ Yaml yaml = new Yaml(options);
+ String output = yaml.dump(list);
+ assertEquals(
+ "- 2008-12-19T11:06:01.159Z\n- 2008-12-19T11:06:01.059Z\n- 2008-12-19T11:06:01.009Z\n- 2008-12-19T11:06:01.150Z\n- 2008-12-19T11:06:01.100Z\n- 2008-12-19T11:06:01Z\n- 2008-12-19T11:06:00Z\n",
+ output);
+ }
+
+ public void testEmptyArray() {
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(new String[0]);
+ assertEquals("[]\n", output);
+ }
+
+ public void testStyle() {
+ List<Integer> list = new LinkedList<Integer>();
+ list.add(new Integer(1));
+ list.add(new Integer(1));
+ Map<String, Object> map = new HashMap<String, Object>();
+ map.put("list", list);
+ map.put("name", "Ubuntu");
+ map.put("age", 5);
+ DumperOptions options = new DumperOptions();
+ options.setDefaultStyle(DumperOptions.DefaultScalarStyle.DOUBLE_QUOTED);
+ options.setDefaultFlowStyle(DumperOptions.DefaultFlowStyle.BLOCK);
+ Yaml yaml = new Yaml(options);
+ String output = yaml.dump(map);
+ assertTrue(output.contains("\"age\": !!int \"5\""));
+ assertTrue(output.contains("\"name\": \"Ubuntu\""));
+ assertTrue(output.contains("- !!int \"1\""));
+ }
+
+ public void testStyle2() {
+ List<Integer> list = new LinkedList<Integer>();
+ list.add(new Integer(1));
+ list.add(new Integer(1));
+ Map<String, Object> map = new LinkedHashMap<String, Object>();
+ map.put("age", 5);
+ map.put("name", "Ubuntu");
+ map.put("list", list);
+ DumperOptions options = new DumperOptions();
+ options.setDefaultStyle(DumperOptions.DefaultScalarStyle.SINGLE_QUOTED);
+ options.setDefaultFlowStyle(DumperOptions.DefaultFlowStyle.FLOW);
+ Yaml yaml = new Yaml(options);
+ String output = yaml.dump(map);
+ assertEquals("{'age': !!int '5', 'name': 'Ubuntu', 'list': [!!int '1', !!int '1']}\n",
+ output);
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/resolver/RagelMachine.java b/src/test/java/org/yaml/snakeyaml/resolver/RagelMachine.java
new file mode 100644
index 00000000..324d869b
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/resolver/RagelMachine.java
@@ -0,0 +1,317 @@
+// line 1 "RagelMachine.rl"
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.resolver;
+
+//Source for Ragel 6.3
+
+/**
+ * Generated by Ragel 6.3 (http://www.complang.org/ragel/)
+ *
+ * @see http://www.complang.org/ragel/
+ */
+public class RagelMachine {
+
+ // line 15 "RagelMachine.java"
+ private static byte[] init__snakeyaml_actions_0() {
+ return new byte[] { 0, 1, 0, 1, 1, 1, 2, 1, 3, 1, 4, 1, 5, 1, 6 };
+ }
+
+ private static final byte _snakeyaml_actions[] = init__snakeyaml_actions_0();
+
+ private static short[] init__snakeyaml_key_offsets_0() {
+ return new short[] { 0, 0, 20, 24, 28, 30, 32, 34, 35, 36, 37, 42, 46, 50, 52, 56, 59, 66,
+ 70, 74, 80, 82, 83, 84, 85, 87, 90, 92, 98, 102, 105, 106, 108, 110, 111, 113, 115,
+ 120, 122, 124, 126, 130, 132, 133, 135, 141, 147, 152, 157, 158, 160, 161, 162,
+ 163, 164, 165, 166, 170, 171, 172, 173, 174, 178, 179, 180, 182, 183, 184, 186,
+ 187, 188, 189, 191, 193, 194, 195, 195, 200, 202, 202, 211, 218, 224, 227, 234,
+ 239, 243, 245, 250, 253, 254, 263, 270, 277, 285, 291, 294, 295, 295, 302, 306,
+ 311, 316, 321, 327, 327, 327 };
+ }
+
+ private static final short _snakeyaml_key_offsets[] = init__snakeyaml_key_offsets_0();
+
+ private static char[] init__snakeyaml_trans_keys_0() {
+ return new char[] { 32, 43, 45, 46, 48, 60, 61, 70, 78, 79, 84, 89, 102, 110, 111, 116,
+ 121, 126, 49, 57, 46, 48, 49, 57, 73, 105, 48, 57, 43, 45, 48, 57, 78, 110, 70,
+ 102, 110, 46, 58, 95, 48, 57, 48, 53, 54, 57, 46, 58, 48, 57, 46, 58, 46, 95, 48,
+ 57, 95, 48, 49, 95, 48, 57, 65, 70, 97, 102, 48, 53, 54, 57, 48, 53, 54, 57, 73,
+ 78, 105, 110, 48, 57, 65, 97, 78, 97, 110, 48, 57, 45, 48, 57, 48, 57, 9, 32, 84,
+ 116, 48, 57, 9, 32, 48, 57, 58, 48, 57, 58, 48, 57, 48, 57, 58, 48, 57, 48, 57, 9,
+ 32, 43, 45, 90, 48, 57, 48, 57, 48, 57, 9, 32, 84, 116, 48, 57, 45, 48, 57, 9, 32,
+ 84, 116, 48, 57, 45, 46, 58, 95, 48, 57, 46, 58, 95, 48, 57, 46, 58, 95, 48, 57,
+ 60, 65, 97, 76, 83, 69, 108, 115, 101, 79, 85, 111, 117, 76, 76, 108, 108, 70, 78,
+ 102, 110, 70, 102, 82, 114, 85, 117, 69, 101, 83, 115, 97, 111, 117, 102, 110, 114,
+ 101, 69, 95, 101, 48, 57, 48, 57, 46, 58, 95, 98, 120, 48, 55, 56, 57, 46, 58, 95,
+ 48, 55, 56, 57, 46, 95, 48, 55, 56, 57, 95, 48, 49, 95, 48, 57, 65, 70, 97, 102,
+ 46, 58, 95, 48, 57, 46, 58, 48, 57, 46, 58, 46, 58, 95, 48, 57, 58, 48, 57, 58, 46,
+ 58, 95, 98, 120, 48, 55, 56, 57, 46, 58, 95, 48, 55, 56, 57, 46, 58, 95, 48, 55,
+ 56, 57, 45, 46, 58, 95, 48, 55, 56, 57, 9, 32, 43, 45, 46, 90, 58, 48, 57, 58, 9,
+ 32, 43, 45, 90, 48, 57, 9, 32, 84, 116, 46, 58, 95, 48, 57, 46, 58, 95, 48, 57, 46,
+ 58, 95, 48, 57, 45, 46, 58, 95, 48, 57, 0 };
+ }
+
+ private static final char _snakeyaml_trans_keys[] = init__snakeyaml_trans_keys_0();
+
+ private static byte[] init__snakeyaml_single_lengths_0() {
+ return new byte[] { 0, 18, 2, 2, 2, 0, 2, 1, 1, 1, 3, 0, 2, 2, 2, 1, 1, 0, 0, 4, 2, 1, 1,
+ 1, 0, 1, 0, 4, 2, 1, 1, 0, 0, 1, 0, 0, 5, 0, 0, 0, 4, 0, 1, 0, 4, 4, 3, 3, 1, 2, 1,
+ 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 4, 1, 1, 2, 1, 1, 2, 1, 1, 1, 2, 2, 1, 1, 0, 3, 0, 0,
+ 5, 3, 2, 1, 1, 3, 2, 2, 3, 1, 1, 5, 3, 3, 4, 6, 1, 1, 0, 5, 4, 3, 3, 3, 4, 0, 0, 0 };
+ }
+
+ private static final byte _snakeyaml_single_lengths[] = init__snakeyaml_single_lengths_0();
+
+ private static byte[] init__snakeyaml_range_lengths_0() {
+ return new byte[] { 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 2, 1, 0, 1, 1, 3, 2, 2, 1, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 2,
+ 2, 2, 1, 3, 1, 1, 0, 1, 1, 0, 2, 2, 2, 2, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0 };
+ }
+
+ private static final byte _snakeyaml_range_lengths[] = init__snakeyaml_range_lengths_0();
+
+ private static short[] init__snakeyaml_index_offsets_0() {
+ return new short[] { 0, 0, 20, 24, 28, 31, 33, 36, 38, 40, 42, 47, 50, 54, 57, 61, 64, 69,
+ 72, 75, 81, 84, 86, 88, 90, 92, 95, 97, 103, 107, 110, 112, 114, 116, 118, 120,
+ 122, 128, 130, 132, 134, 139, 141, 143, 145, 151, 157, 162, 167, 169, 172, 174,
+ 176, 178, 180, 182, 184, 189, 191, 193, 195, 197, 202, 204, 206, 209, 211, 213,
+ 216, 218, 220, 222, 225, 228, 230, 232, 233, 238, 240, 241, 249, 255, 260, 263,
+ 268, 273, 277, 280, 285, 288, 290, 298, 304, 310, 317, 324, 327, 329, 330, 337,
+ 342, 347, 352, 357, 363, 364, 365 };
+ }
+
+ private static final short _snakeyaml_index_offsets[] = init__snakeyaml_index_offsets_0();
+
+ private static byte[] init__snakeyaml_indicies_0() {
+ return new byte[] { 0, 2, 2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 0, 5, 1, 18,
+ 19, 20, 1, 22, 23, 21, 1, 24, 24, 1, 25, 1, 26, 27, 1, 28, 1, 28, 1, 27, 1, 21, 30,
+ 31, 29, 1, 32, 33, 1, 25, 30, 33, 1, 25, 30, 1, 21, 31, 31, 1, 34, 34, 1, 35, 35,
+ 35, 35, 1, 36, 37, 1, 38, 39, 1, 22, 40, 23, 41, 21, 1, 42, 42, 1, 28, 1, 43, 1,
+ 28, 1, 44, 1, 45, 46, 1, 47, 1, 48, 48, 50, 50, 49, 1, 48, 48, 51, 1, 53, 52, 1,
+ 53, 1, 54, 1, 55, 1, 56, 1, 57, 1, 58, 1, 59, 59, 60, 60, 61, 1, 62, 1, 63, 1, 61,
+ 1, 48, 48, 50, 50, 1, 51, 1, 64, 1, 65, 1, 48, 48, 50, 50, 66, 1, 67, 21, 30, 31,
+ 29, 1, 21, 30, 31, 68, 1, 21, 30, 31, 69, 1, 70, 1, 71, 72, 1, 73, 1, 74, 1, 75, 1,
+ 76, 1, 77, 1, 75, 1, 75, 78, 75, 79, 1, 80, 1, 0, 1, 81, 1, 0, 1, 82, 75, 83, 75,
+ 1, 75, 1, 75, 1, 84, 85, 1, 74, 1, 77, 1, 86, 87, 1, 75, 1, 75, 1, 72, 1, 75, 79,
+ 1, 83, 75, 1, 85, 1, 87, 1, 1, 88, 21, 88, 21, 1, 25, 1, 1, 21, 30, 90, 91, 92, 89,
+ 29, 1, 21, 30, 90, 89, 29, 1, 21, 90, 90, 31, 1, 34, 34, 1, 35, 35, 35, 35, 1, 21,
+ 93, 94, 20, 1, 25, 93, 37, 1, 25, 93, 1, 21, 95, 94, 94, 1, 95, 39, 1, 95, 1, 21,
+ 30, 90, 91, 92, 96, 97, 1, 21, 30, 90, 98, 69, 1, 21, 30, 90, 99, 68, 1, 67, 21,
+ 30, 90, 89, 29, 1, 59, 59, 60, 60, 100, 61, 1, 102, 101, 1, 102, 1, 1, 59, 59, 60,
+ 60, 61, 100, 1, 48, 48, 50, 50, 1, 21, 93, 94, 103, 1, 21, 93, 94, 104, 1, 21, 93,
+ 94, 105, 1, 67, 21, 93, 94, 20, 1, 1, 1, 1, 0 };
+ }
+
+ private static final byte _snakeyaml_indicies[] = init__snakeyaml_indicies_0();
+
+ private static byte[] init__snakeyaml_trans_targs_0() {
+ return new byte[] { 75, 0, 2, 19, 90, 100, 48, 105, 49, 56, 61, 64, 67, 70, 71, 72, 73, 74,
+ 3, 79, 84, 76, 6, 9, 5, 77, 7, 8, 78, 10, 11, 14, 12, 13, 82, 83, 85, 86, 88, 89,
+ 20, 22, 21, 23, 25, 26, 42, 27, 28, 40, 41, 29, 30, 31, 32, 33, 34, 35, 94, 36, 37,
+ 97, 95, 39, 43, 44, 99, 24, 45, 46, 104, 50, 53, 51, 52, 106, 54, 55, 57, 59, 58,
+ 60, 62, 63, 65, 66, 68, 69, 4, 80, 81, 15, 16, 17, 87, 18, 91, 47, 92, 93, 98, 96,
+ 38, 101, 102, 103 };
+ }
+
+ private static final byte _snakeyaml_trans_targs[] = init__snakeyaml_trans_targs_0();
+
+ // private static byte[] init__snakeyaml_trans_actions_0() {
+ // return new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ // 0, 0, 0, 0, 0, 0,
+ // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ // 0, 0, 0, 0,
+ // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ // 0, 0, 0, 0,
+ // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ // 0, 0 };
+ // }
+
+ // private static final byte _snakeyaml_trans_actions[] =
+ // init__snakeyaml_trans_actions_0();
+
+ private static byte[] init__snakeyaml_eof_actions_0() {
+ return new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 11, 11, 11,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 13, 13, 13, 13, 13, 13, 9, 9, 9, 9, 3,
+ 7, 1 };
+ }
+
+ private static final byte _snakeyaml_eof_actions[] = init__snakeyaml_eof_actions_0();
+
+ static final int snakeyaml_start = 1;
+ static final int snakeyaml_error = 0;
+
+ static final int snakeyaml_en_main = 1;
+
+ // line 53 "RagelMachine.rl"
+
+ public String scan(String scalar) {
+ if (scalar == null) {
+ throw new NullPointerException("Scalar must be provided.");
+ }
+ String tag = null;
+ int cs = 0;
+ int p = 0;
+ int pe = scalar.length();
+ int eof = pe;
+ char[] data;
+ if (pe == 0) {
+ // NULL value
+ data = new char[] { '~' };
+ pe = 1;
+ eof = 1;
+ } else {
+ data = scalar.toCharArray();
+ }
+
+ // line 257 "RagelMachine.java"
+ {
+ cs = snakeyaml_start;
+ }
+
+ // line 262 "RagelMachine.java"
+ {
+ int _klen;
+ int _trans = 0;
+ int _keys;
+ int _goto_targ = 0;
+
+ _goto: while (true) {
+ switch (_goto_targ) {
+ case 0:
+ if (p == pe) {
+ _goto_targ = 4;
+ continue _goto;
+ }
+ if (cs == 0) {
+ _goto_targ = 5;
+ continue _goto;
+ }
+ case 1:
+ _match: do {
+ _keys = _snakeyaml_key_offsets[cs];
+ _trans = _snakeyaml_index_offsets[cs];
+ _klen = _snakeyaml_single_lengths[cs];
+ if (_klen > 0) {
+ int _lower = _keys;
+ int _mid;
+ int _upper = _keys + _klen - 1;
+ while (true) {
+ if (_upper < _lower)
+ break;
+
+ _mid = _lower + ((_upper - _lower) >> 1);
+ if (data[p] < _snakeyaml_trans_keys[_mid])
+ _upper = _mid - 1;
+ else if (data[p] > _snakeyaml_trans_keys[_mid])
+ _lower = _mid + 1;
+ else {
+ _trans += (_mid - _keys);
+ break _match;
+ }
+ }
+ _keys += _klen;
+ _trans += _klen;
+ }
+
+ _klen = _snakeyaml_range_lengths[cs];
+ if (_klen > 0) {
+ int _lower = _keys;
+ int _mid;
+ int _upper = _keys + (_klen << 1) - 2;
+ while (true) {
+ if (_upper < _lower)
+ break;
+
+ _mid = _lower + (((_upper - _lower) >> 1) & ~1);
+ if (data[p] < _snakeyaml_trans_keys[_mid])
+ _upper = _mid - 2;
+ else if (data[p] > _snakeyaml_trans_keys[_mid + 1])
+ _lower = _mid + 2;
+ else {
+ _trans += ((_mid - _keys) >> 1);
+ break _match;
+ }
+ }
+ _trans += _klen;
+ }
+ } while (false);
+
+ _trans = _snakeyaml_indicies[_trans];
+ cs = _snakeyaml_trans_targs[_trans];
+
+ case 2:
+ if (cs == 0) {
+ _goto_targ = 5;
+ continue _goto;
+ }
+ if (++p != pe) {
+ _goto_targ = 1;
+ continue _goto;
+ }
+ case 4:
+ if (p == eof) {
+ int __acts = _snakeyaml_eof_actions[cs];
+ int __nacts = (int) _snakeyaml_actions[__acts++];
+ while (__nacts-- > 0) {
+ switch (_snakeyaml_actions[__acts++]) {
+ case 0:
+ // line 14 "RagelMachine.rl"
+ {
+ tag = "tag:yaml.org,2002:bool";
+ }
+ break;
+ case 1:
+ // line 15 "RagelMachine.rl"
+ {
+ tag = "tag:yaml.org,2002:merge";
+ }
+ break;
+ case 2:
+ // line 16 "RagelMachine.rl"
+ {
+ tag = "tag:yaml.org,2002:null";
+ }
+ break;
+ case 3:
+ // line 17 "RagelMachine.rl"
+ {
+ tag = "tag:yaml.org,2002:value";
+ }
+ break;
+ case 4:
+ // line 18 "RagelMachine.rl"
+ {
+ tag = "tag:yaml.org,2002:int";
+ }
+ break;
+ case 5:
+ // line 19 "RagelMachine.rl"
+ {
+ tag = "tag:yaml.org,2002:float";
+ }
+ break;
+ case 6:
+ // line 20 "RagelMachine.rl"
+ {
+ tag = "tag:yaml.org,2002:timestamp";
+ }
+ break;
+ // line 377 "RagelMachine.java"
+ }
+ }
+ }
+
+ case 5:
+ }
+ break;
+ }
+ }
+ // line 77 "RagelMachine.rl"
+
+ return tag;
+ }
+} \ No newline at end of file
diff --git a/src/test/java/org/yaml/snakeyaml/resolver/RagelMachineTest.java b/src/test/java/org/yaml/snakeyaml/resolver/RagelMachineTest.java
new file mode 100644
index 00000000..1ad62ccc
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/resolver/RagelMachineTest.java
@@ -0,0 +1,104 @@
+package org.yaml.snakeyaml.resolver;
+
+import junit.framework.TestCase;
+
+public class RagelMachineTest extends TestCase {
+ private RagelMachine machine = new RagelMachine();
+
+ public void testScan() {
+ assertNull(machine.scan("abc"));
+ }
+
+ public void testNullPointerException() {
+ try {
+ machine.scan(null);
+ fail("null must not be accepted.");
+ } catch (NullPointerException e) {
+ assertEquals("Scalar must be provided.", e.getMessage());
+ }
+ }
+
+ public void testScanBoolean() {
+ assertEquals("tag:yaml.org,2002:bool", machine.scan("true"));
+ assertEquals("tag:yaml.org,2002:bool", machine.scan("True"));
+ assertEquals("tag:yaml.org,2002:bool", machine.scan("TRUE"));
+ assertEquals("tag:yaml.org,2002:bool", machine.scan("false"));
+ assertEquals("tag:yaml.org,2002:bool", machine.scan("False"));
+ assertEquals("tag:yaml.org,2002:bool", machine.scan("FALSE"));
+ assertEquals("tag:yaml.org,2002:bool", machine.scan("on"));
+ assertEquals("tag:yaml.org,2002:bool", machine.scan("ON"));
+ assertEquals("tag:yaml.org,2002:bool", machine.scan("On"));
+ assertEquals("tag:yaml.org,2002:bool", machine.scan("off"));
+ assertEquals("tag:yaml.org,2002:bool", machine.scan("Off"));
+ assertEquals("tag:yaml.org,2002:bool", machine.scan("OFF"));
+ assertEquals("tag:yaml.org,2002:bool", machine.scan("on"));
+ assertEquals("tag:yaml.org,2002:bool", machine.scan("ON"));
+ assertEquals("tag:yaml.org,2002:bool", machine.scan("On"));
+ assertEquals("tag:yaml.org,2002:bool", machine.scan("off"));
+ assertEquals("tag:yaml.org,2002:bool", machine.scan("Off"));
+ assertEquals("tag:yaml.org,2002:bool", machine.scan("OFF"));
+ }
+
+ public void testScanNull() {
+ assertEquals("tag:yaml.org,2002:null", machine.scan("null"));
+ assertEquals("tag:yaml.org,2002:null", machine.scan("Null"));
+ assertEquals("tag:yaml.org,2002:null", machine.scan("NULL"));
+ assertEquals("tag:yaml.org,2002:null", machine.scan("~"));
+ assertEquals("tag:yaml.org,2002:null", machine.scan(" "));
+ assertEquals("tag:yaml.org,2002:null", machine.scan(""));
+ }
+
+ public void testScanMerge() {
+ assertEquals("tag:yaml.org,2002:merge", machine.scan("<<"));
+ }
+
+ public void testScanValue() {
+ assertEquals("tag:yaml.org,2002:value", machine.scan("="));
+ }
+
+ public void testScanInt() {
+ assertEquals("tag:yaml.org,2002:int", machine.scan("0"));
+ assertEquals("tag:yaml.org,2002:int", machine.scan("1"));
+ assertEquals("tag:yaml.org,2002:int", machine.scan("-0"));
+ assertEquals("tag:yaml.org,2002:int", machine.scan("-9"));
+ assertEquals("tag:yaml.org,2002:int", machine.scan("0b0011"));
+ assertEquals("tag:yaml.org,2002:int", machine.scan("0x12ef"));
+ assertEquals("tag:yaml.org,2002:int", machine.scan("0123"));
+ assertEquals("tag:yaml.org,2002:int", machine.scan("1_000"));
+ assertEquals("tag:yaml.org,2002:int", machine.scan("1_000_000"));
+ assertEquals("tag:yaml.org,2002:int", machine.scan("+0"));
+ assertEquals("tag:yaml.org,2002:int", machine.scan("+10"));
+ assertEquals("tag:yaml.org,2002:int", machine.scan("1__000"));
+ assertEquals("tag:yaml.org,2002:int", machine.scan("24:12:34"));
+ assertEquals("tag:yaml.org,2002:int", machine.scan("240:12:34"));
+ }
+
+ public void testScanFloat() {
+ assertEquals("tag:yaml.org,2002:float", machine.scan("1.0"));
+ assertEquals("tag:yaml.org,2002:float", machine.scan("-0.0"));
+ assertEquals("tag:yaml.org,2002:float", machine.scan("+2.2310"));
+ assertEquals("tag:yaml.org,2002:float", machine.scan("1.0e+12"));
+ assertEquals("tag:yaml.org,2002:float", machine.scan("1.345e-3"));
+ assertEquals("tag:yaml.org,2002:float", machine.scan("190:20:30.15"));
+ assertEquals("tag:yaml.org,2002:float", machine.scan("-.inf"));
+ assertEquals("tag:yaml.org,2002:float", machine.scan("+.INF"));
+ assertEquals("tag:yaml.org,2002:float", machine.scan(".Inf"));
+ assertEquals("tag:yaml.org,2002:float", machine.scan(".nan"));
+ assertEquals("tag:yaml.org,2002:float", machine.scan(".NaN"));
+ assertEquals("tag:yaml.org,2002:float", machine.scan(".NAN"));
+ assertEquals("tag:yaml.org,2002:float", machine.scan("1_000.5"));
+ assertEquals("tag:yaml.org,2002:float", machine.scan("1.023_456"));
+ assertEquals("tag:yaml.org,2002:float", machine.scan("-1_123.45"));
+ assertEquals("tag:yaml.org,2002:float", machine.scan(".5"));
+ assertEquals("tag:yaml.org,2002:float", machine.scan("1.E+1"));
+ assertNull(machine.scan("0x1,1"), machine.scan("0x1,1"));
+ }
+
+ public void testScanTimestamp() {
+ assertEquals("tag:yaml.org,2002:timestamp", machine.scan("2009-02-28"));
+ assertEquals("tag:yaml.org,2002:timestamp", machine.scan("2001-12-15T02:59:43.1Z"));
+ assertEquals("tag:yaml.org,2002:timestamp", machine.scan("2001-12-14t21:59:43.10-05:00"));
+ assertEquals("tag:yaml.org,2002:timestamp", machine.scan("2001-12-14 21:59:43.10 -5"));
+ assertEquals("tag:yaml.org,2002:timestamp", machine.scan("2001-12-15 2:59:43.10"));
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/resolver/ResolverTest.java b/src/test/java/org/yaml/snakeyaml/resolver/ResolverTest.java
new file mode 100644
index 00000000..94bd291f
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/resolver/ResolverTest.java
@@ -0,0 +1,141 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.resolver;
+
+import java.awt.Point;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Dumper;
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Loader;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.Construct;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.ScalarNode;
+import org.yaml.snakeyaml.representer.Represent;
+import org.yaml.snakeyaml.representer.Representer;
+
+public class ResolverTest extends TestCase {
+
+ @SuppressWarnings("unchecked")
+ public void testAddImplicitResolver() {
+ Dumper dumper = new Dumper(new MyRepresenter(), new DumperOptions());
+ Loader loader = new Loader(new MyConstructor());
+ Yaml yaml = new Yaml(loader, dumper);
+ Pattern regexp = Pattern.compile("\\d\\d-\\d\\d-\\d\\d\\d");
+ yaml.addImplicitResolver("tag:yaml.org,2002:Phone", regexp, "0123456789");
+ Phone phone1 = new Phone("12-34-567");
+ Phone phone2 = new Phone("11-22-333");
+ Phone phone3 = new Phone("44-55-777");
+ List<Phone> etalonList = new LinkedList<Phone>();
+ etalonList.add(phone1);
+ etalonList.add(phone2);
+ etalonList.add(phone3);
+ String output = yaml.dump(etalonList);
+ assertEquals("[12-34-567, 11-22-333, 44-55-777]\n", output);
+ List<Phone> parsedList = (List<Phone>) yaml.load(output);
+ assertEquals(3, parsedList.size());
+ assertEquals(phone1, parsedList.get(0));
+ assertEquals(phone2, parsedList.get(1));
+ assertEquals(phone3, parsedList.get(2));
+ assertEquals(etalonList, parsedList);
+ }
+
+ public void testAddImplicitResolver2() {
+ Dumper dumper = new Dumper(new PointRepresenter(), new DumperOptions());
+ Yaml yaml = new Yaml(dumper);
+ Pattern regexp = Pattern.compile("\\d\\d-\\d\\d-\\d\\d\\d");
+ yaml.addImplicitResolver("tag:yaml.org,2002:Phone", regexp, "\0");
+ Pattern regexp2 = Pattern.compile("x\\d_y\\d");
+ // try any scalar, and not only those which start with 'x'
+ yaml.addImplicitResolver("tag:yaml.org,2002:Point", regexp2, null);
+ Map<String, Object> map = new LinkedHashMap<String, Object>();
+ map.put("a", new Phone("12-34-567"));
+ map.put("b", new Point(1, 5));
+ String output = yaml.dump(map);
+ assertEquals("{a: 12-34-567, b: x1_y5}\n", output);
+ }
+
+ class Phone {
+ private String number;
+
+ public Phone(String n) {
+ this.number = n;
+ }
+
+ public String getNumber() {
+ return number;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof Phone)) {
+ return false;
+ }
+ return toString().equals(obj.toString());
+ }
+
+ @Override
+ public String toString() {
+ return "Phone: " + number;
+ }
+ }
+
+ class MyRepresenter extends Representer {
+ public MyRepresenter() {
+ this.representers.put(Phone.class, new RepresentPhone());
+ }
+
+ private class RepresentPhone implements Represent {
+ public Node representData(Object data) {
+ Phone phone = (Phone) data;
+ String value = phone.getNumber();
+ return representScalar("tag:yaml.org,2002:Phone", value);
+ }
+ }
+ }
+
+ class MyConstructor extends Constructor {
+ public MyConstructor() {
+ this.yamlConstructors.put("tag:yaml.org,2002:Phone", new ConstuctPhone());
+ }
+
+ private class ConstuctPhone implements Construct {
+ public Object construct(Node node) {
+ String val = (String) constructScalar((ScalarNode) node);
+ return new Phone(val);
+ }
+ }
+ }
+
+ class PointRepresenter extends Representer {
+ public PointRepresenter() {
+ this.representers.put(Point.class, new RepresentPoint());
+ this.representers.put(Phone.class, new RepresentPhone());
+ }
+
+ private class RepresentPoint implements Represent {
+ public Node representData(Object data) {
+ Point phone = (Point) data;
+ String value = "x" + (int) phone.getX() + "_y" + (int) phone.getY();
+ return representScalar("tag:yaml.org,2002:Point", value);
+ }
+ }
+
+ private class RepresentPhone implements Represent {
+ public Node representData(Object data) {
+ Phone phone = (Phone) data;
+ String value = phone.getNumber();
+ return representScalar("tag:yaml.org,2002:Phone", value);
+ }
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/resolver/ResolverTupleTest.java b/src/test/java/org/yaml/snakeyaml/resolver/ResolverTupleTest.java
new file mode 100644
index 00000000..763291af
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/resolver/ResolverTupleTest.java
@@ -0,0 +1,16 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.resolver;
+
+import java.util.regex.Pattern;
+
+import junit.framework.TestCase;
+
+public class ResolverTupleTest extends TestCase {
+
+ public void testToString() {
+ ResolverTuple tuple = new ResolverTuple("dice", Pattern.compile("\\d+"));
+ assertEquals("Tuple tag=dice regexp=\\d+", tuple.toString());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/scanner/ScannerImplTest.java b/src/test/java/org/yaml/snakeyaml/scanner/ScannerImplTest.java
new file mode 100644
index 00000000..4486522d
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/scanner/ScannerImplTest.java
@@ -0,0 +1,47 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.scanner;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.error.Mark;
+import org.yaml.snakeyaml.reader.Reader;
+import org.yaml.snakeyaml.tokens.BlockEndToken;
+import org.yaml.snakeyaml.tokens.BlockMappingStartToken;
+import org.yaml.snakeyaml.tokens.KeyToken;
+import org.yaml.snakeyaml.tokens.ScalarToken;
+import org.yaml.snakeyaml.tokens.StreamEndToken;
+import org.yaml.snakeyaml.tokens.StreamStartToken;
+import org.yaml.snakeyaml.tokens.Token;
+import org.yaml.snakeyaml.tokens.ValueToken;
+
+public class ScannerImplTest extends TestCase {
+
+ @SuppressWarnings("unchecked")
+ public void testGetToken() {
+ String data = "string: abcd";
+ Reader reader = new Reader(data);
+ Scanner scanner = new ScannerImpl(reader);
+
+ Mark dummy = new Mark("dummy", 0, 0, 0, "", 0);
+ LinkedList<Token> etalonTokens = new LinkedList<Token>();
+ etalonTokens.add(new StreamStartToken(dummy, dummy));
+ etalonTokens.add(new BlockMappingStartToken(dummy, dummy));
+ etalonTokens.add(new KeyToken(dummy, dummy));
+ etalonTokens.add(new ScalarToken("string", true, dummy, dummy, (char) 0));
+ etalonTokens.add(new ValueToken(dummy, dummy));
+ etalonTokens.add(new ScalarToken("abcd", true, dummy, dummy, (char) 0));
+ etalonTokens.add(new BlockEndToken(dummy, dummy));
+ etalonTokens.add(new StreamEndToken(dummy, dummy));
+ while (scanner.checkToken(new ArrayList())) {
+ assertEquals(etalonTokens.removeFirst(), scanner.getToken());
+ // System.out.println(scanner.getToken());
+ }
+ assertFalse("Must contain no more tokens: " + scanner.getToken(), scanner
+ .checkToken(new ArrayList()));
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/scanner/SimpleKeyTest.java b/src/test/java/org/yaml/snakeyaml/scanner/SimpleKeyTest.java
new file mode 100644
index 00000000..ca4a4075
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/scanner/SimpleKeyTest.java
@@ -0,0 +1,14 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.scanner;
+
+import junit.framework.TestCase;
+
+public class SimpleKeyTest extends TestCase {
+
+ public void testToString() {
+ SimpleKey key = new SimpleKey(1, false, 5, 3, 2, null);
+ assertTrue(key.toString().contains("SimpleKey"));
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/serializer/SerializerTest.java b/src/test/java/org/yaml/snakeyaml/serializer/SerializerTest.java
new file mode 100644
index 00000000..898ff034
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/serializer/SerializerTest.java
@@ -0,0 +1,89 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.serializer;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.text.NumberFormat;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.emitter.Emitter;
+import org.yaml.snakeyaml.nodes.ScalarNode;
+import org.yaml.snakeyaml.resolver.Resolver;
+
+public class SerializerTest extends TestCase {
+ private Serializer serializer;
+
+ @Override
+ protected void setUp() throws Exception {
+ DumperOptions config = new DumperOptions();
+ StringWriter writer = new StringWriter();
+ serializer = new Serializer(new Emitter(writer, config), new Resolver(), config);
+ }
+
+ public void testSerializerIsAlreadyOpened() throws IOException {
+ serializer.open();
+ try {
+ serializer.open();
+ fail();
+ } catch (RuntimeException e) {
+ assertEquals("serializer is already opened", e.getMessage());
+ }
+ }
+
+ public void testSerializerIsClosed1() throws IOException {
+ serializer.open();
+ serializer.close();
+ try {
+ serializer.open();
+ fail();
+ } catch (RuntimeException e) {
+ assertEquals("serializer is closed", e.getMessage());
+ }
+ }
+
+ public void testSerializerIsClosed2() throws IOException {
+ serializer.open();
+ serializer.close();
+ try {
+ serializer.serialize(new ScalarNode("!foo", "bar", null, null, (char) 0));
+ fail();
+ } catch (RuntimeException e) {
+ assertEquals("serializer is closed", e.getMessage());
+ }
+ }
+
+ public void testSerializerIsClosed3() throws IOException {
+ serializer.open();
+ serializer.close();
+ serializer.close();// no problem to close twice
+ }
+
+ public void testSerializerIsNotOpened1() throws IOException {
+ try {
+ serializer.close();
+ fail();
+ } catch (RuntimeException e) {
+ assertEquals("serializer is not opened", e.getMessage());
+ }
+ }
+
+ public void testSerializerIsNotOpened2() throws IOException {
+ try {
+ serializer.serialize(new ScalarNode("!foo", "bar", null, null, (char) 0));
+ fail();
+ } catch (RuntimeException e) {
+ assertEquals("serializer is not opened", e.getMessage());
+ }
+ }
+
+ public void testGenerateAnchor() {
+ NumberFormat format = NumberFormat.getNumberInstance();
+ format.setMinimumIntegerDigits(3);
+ String anchor = format.format(3L);
+ assertEquals("003", anchor);
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/tokens/AliasTokenTest.java b/src/test/java/org/yaml/snakeyaml/tokens/AliasTokenTest.java
new file mode 100644
index 00000000..c8aed69e
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/tokens/AliasTokenTest.java
@@ -0,0 +1,29 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.error.Mark;
+
+public class AliasTokenTest extends TestCase {
+
+ public void testEquals() {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ AliasToken token = new AliasToken("*id123", mark, mark);
+ assertFalse(token.equals(mark));
+ }
+
+ public void testGetArguments() {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ AliasToken token = new AliasToken("*id123", mark, mark);
+ assertEquals("value=*id123", token.getArguments());
+ }
+
+ public void testGetTokenId() {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ AliasToken token = new AliasToken("&id123", mark, mark);
+ assertEquals("<alias>", token.getTokenId());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/tokens/AnchorTokenTest.java b/src/test/java/org/yaml/snakeyaml/tokens/AnchorTokenTest.java
new file mode 100644
index 00000000..2352a459
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/tokens/AnchorTokenTest.java
@@ -0,0 +1,23 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.error.Mark;
+
+public class AnchorTokenTest extends TestCase {
+
+ public void testGetArguments() {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ AnchorToken token = new AnchorToken("&id123", mark, mark);
+ assertEquals("value=&id123", token.getArguments());
+ }
+
+ public void testGetTokenId() {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ AnchorToken token = new AnchorToken("&id123", mark, mark);
+ assertEquals("<anchor>", token.getTokenId());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/tokens/BlockEndTokenTest.java b/src/test/java/org/yaml/snakeyaml/tokens/BlockEndTokenTest.java
new file mode 100644
index 00000000..38cb49b1
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/tokens/BlockEndTokenTest.java
@@ -0,0 +1,23 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.error.Mark;
+
+public class BlockEndTokenTest extends TestCase {
+
+ public void testGetArguments() {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ BlockEndToken token = new BlockEndToken(mark, mark);
+ assertEquals("", token.getArguments());
+ }
+
+ public void testGetTokenId() {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ BlockEndToken token = new BlockEndToken(mark, mark);
+ assertEquals("<block end>", token.getTokenId());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/tokens/BlockEntryTokenTest.java b/src/test/java/org/yaml/snakeyaml/tokens/BlockEntryTokenTest.java
new file mode 100644
index 00000000..869c2871
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/tokens/BlockEntryTokenTest.java
@@ -0,0 +1,18 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.error.Mark;
+
+public class BlockEntryTokenTest extends TestCase {
+
+ public void testGetTokenId() {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ BlockEntryToken token = new BlockEntryToken(mark, mark);
+ assertEquals("-", token.getTokenId());
+ }
+
+}
diff --git a/src/test/java/org/yaml/snakeyaml/tokens/BlockSequenceStartTokenTest.java b/src/test/java/org/yaml/snakeyaml/tokens/BlockSequenceStartTokenTest.java
new file mode 100644
index 00000000..38e4096e
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/tokens/BlockSequenceStartTokenTest.java
@@ -0,0 +1,17 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.error.Mark;
+
+public class BlockSequenceStartTokenTest extends TestCase {
+
+ public void testGetTokenId() {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ BlockSequenceStartToken token = new BlockSequenceStartToken(mark, mark);
+ assertEquals("<block sequence start>", token.getTokenId());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/tokens/DirectiveTokenTest.java b/src/test/java/org/yaml/snakeyaml/tokens/DirectiveTokenTest.java
new file mode 100644
index 00000000..fd765403
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/tokens/DirectiveTokenTest.java
@@ -0,0 +1,56 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.error.Mark;
+
+public class DirectiveTokenTest extends TestCase {
+
+ public void testGetArguments() {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ DirectiveToken token = new DirectiveToken("YAML", null, mark, mark);
+ assertEquals("name=YAML", token.getArguments());
+ }
+
+ public void testInvalidList() {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ List<Integer> list = new LinkedList<Integer>();
+ list.add(new Integer(1));
+ try {
+ new DirectiveToken("YAML", list, mark, mark);
+ fail("List must have 2 values.");
+ } catch (Exception e) {
+ assertEquals("Two strings must be provided instead of 1", e.getMessage());
+ }
+ }
+
+ public void testTag() {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ List<String> list = new LinkedList<String>();
+ list.add("!foo");
+ list.add("!bar");
+ DirectiveToken token = new DirectiveToken("TAG", list, mark, mark);
+ assertEquals("name=TAG, value=[!foo, !bar]", token.getArguments());
+ }
+
+ public void testList() {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ List<Integer> list = new LinkedList<Integer>();
+ list.add(new Integer(1));
+ list.add(new Integer(1));
+ DirectiveToken token = new DirectiveToken("YAML", list, mark, mark);
+ assertEquals("name=YAML, value=[1, 1]", token.getArguments());
+ }
+
+ public void testGetTokenId() {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ DirectiveToken token = new DirectiveToken("YAML", null, mark, mark);
+ assertEquals("<directive>", token.getTokenId());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/tokens/DocumentEndTokenTest.java b/src/test/java/org/yaml/snakeyaml/tokens/DocumentEndTokenTest.java
new file mode 100644
index 00000000..ed418356
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/tokens/DocumentEndTokenTest.java
@@ -0,0 +1,17 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.error.Mark;
+
+public class DocumentEndTokenTest extends TestCase {
+
+ public void testGetTokenId() {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ DocumentEndToken token = new DocumentEndToken(mark, mark);
+ assertEquals("<document end>", token.getTokenId());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/tokens/DocumentStartTokenTest.java b/src/test/java/org/yaml/snakeyaml/tokens/DocumentStartTokenTest.java
new file mode 100644
index 00000000..253857f0
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/tokens/DocumentStartTokenTest.java
@@ -0,0 +1,17 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.error.Mark;
+
+public class DocumentStartTokenTest extends TestCase {
+
+ public void testGetTokenId() {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ DocumentStartToken token = new DocumentStartToken(mark, mark);
+ assertEquals("<document start>", token.getTokenId());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/tokens/FlowEntryTokenTest.java b/src/test/java/org/yaml/snakeyaml/tokens/FlowEntryTokenTest.java
new file mode 100644
index 00000000..c9d3f0b7
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/tokens/FlowEntryTokenTest.java
@@ -0,0 +1,17 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.error.Mark;
+
+public class FlowEntryTokenTest extends TestCase {
+
+ public void testGetTokenId() {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ FlowEntryToken token = new FlowEntryToken(mark, mark);
+ assertEquals(",", token.getTokenId());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/tokens/FlowMappingStartTokenTest.java b/src/test/java/org/yaml/snakeyaml/tokens/FlowMappingStartTokenTest.java
new file mode 100644
index 00000000..5c5cf4ef
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/tokens/FlowMappingStartTokenTest.java
@@ -0,0 +1,17 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.error.Mark;
+
+public class FlowMappingStartTokenTest extends TestCase {
+
+ public void testGetTokenId() {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ FlowMappingStartToken token = new FlowMappingStartToken(mark, mark);
+ assertEquals("{", token.getTokenId());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/tokens/FlowSequenceStartTokenTest.java b/src/test/java/org/yaml/snakeyaml/tokens/FlowSequenceStartTokenTest.java
new file mode 100644
index 00000000..b79cbb97
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/tokens/FlowSequenceStartTokenTest.java
@@ -0,0 +1,17 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.error.Mark;
+
+public class FlowSequenceStartTokenTest extends TestCase {
+
+ public void testGetTokenId() {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ FlowSequenceStartToken token = new FlowSequenceStartToken(mark, mark);
+ assertEquals("[", token.getTokenId());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/tokens/StreamStartTokenTest.java b/src/test/java/org/yaml/snakeyaml/tokens/StreamStartTokenTest.java
new file mode 100644
index 00000000..8475e4ed
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/tokens/StreamStartTokenTest.java
@@ -0,0 +1,17 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.error.Mark;
+
+public class StreamStartTokenTest extends TestCase {
+
+ public void testGetTokenId() {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ StreamStartToken token = new StreamStartToken(mark, mark);
+ assertEquals("<stream start>", token.getTokenId());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/tokens/TagTokenTest.java b/src/test/java/org/yaml/snakeyaml/tokens/TagTokenTest.java
new file mode 100644
index 00000000..7ab3bb11
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/tokens/TagTokenTest.java
@@ -0,0 +1,33 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.error.Mark;
+
+public class TagTokenTest extends TestCase {
+
+ public void testGetArguments() {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ TagToken token = new TagToken(new String[] { "!foo", "!bar" }, mark, mark);
+ assertEquals("value=[!foo, !bar]", token.getArguments());
+ }
+
+ public void testNoTag() {
+ try {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ new TagToken(new String[] { "!foo" }, mark, mark);
+ fail("Marks must be provided.");
+ } catch (Exception e) {
+ assertEquals("Two strings must be provided instead of 1", e.getMessage());
+ }
+ }
+
+ public void testGetTokenId() {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ TagToken token = new TagToken(new String[] { "!foo", "!bar" }, mark, mark);
+ assertEquals("<tag>", token.getTokenId());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/types/AbstractTest.java b/src/test/java/org/yaml/snakeyaml/types/AbstractTest.java
new file mode 100644
index 00000000..0b464fb3
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/types/AbstractTest.java
@@ -0,0 +1,36 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.types;
+
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+
+public abstract class AbstractTest extends TestCase {
+ @SuppressWarnings("unchecked")
+ protected Map<String, Object> getMap(String data) {
+ Yaml yaml = new Yaml();
+ Map<String, Object> nativeData = (Map<String, Object>) yaml.load(data);
+ return nativeData;
+ }
+
+ protected Object load(String data) {
+ Yaml yaml = new Yaml();
+ Object obj = yaml.load(data);
+ return obj;
+ }
+
+ protected String dump(Object data) {
+ Yaml yaml = new Yaml();
+ return yaml.dump(data);
+ }
+
+ @SuppressWarnings("unchecked")
+ protected Object getMapValue(String data, String key) {
+ Map nativeData = getMap(data);
+ return nativeData.get(key);
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/types/BinaryTagTest.java b/src/test/java/org/yaml/snakeyaml/types/BinaryTagTest.java
new file mode 100644
index 00000000..8dcbecc3
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/types/BinaryTagTest.java
@@ -0,0 +1,64 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.types;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @see http://yaml.org/type/binary.html
+ */
+public class BinaryTagTest extends AbstractTest {
+ String line1 = "R0lGODlhDAAMAIQAAP//9/X17unp5WZmZgAAAOfn515eXvPz7Y6OjuDg4J+fn5";
+ String line2 = "OTk6enp56enmlpaWNjY6Ojo4SEhP/++f/++f/++f/++f/++f/++f/++f/++f/+";
+ String line3 = "+f/++f/++f/++f/++f/++SH+Dk1hZGUgd2l0aCBHSU1QACwAAAAADAAMAAAFLC";
+ String line4 = "AgjoEwnuNAFOhpEMTRiggcz4BNJHrv/zCFcLiwMWYNG84BwwEeECcgggoBADs=";
+ String content = line1 + line2 + line3 + line4;
+
+ public void testBinary() throws IOException {
+ byte[] binary = (byte[]) getMapValue("canonical: !!binary " + content, "canonical");
+ assertEquals((byte) 'G', binary[0]);
+ assertEquals((byte) 'I', binary[1]);
+ assertEquals((byte) 'F', binary[2]);
+ assertEquals((byte) '8', binary[3]);
+ assertEquals((byte) '9', binary[4]);
+ }
+
+ public void testBinary2() throws IOException {
+ byte[] binary = (byte[]) load("!!binary \"MQ==\"");
+ assertEquals(1, binary.length);
+ assertEquals((byte) '1', binary[0]);
+ }
+
+ public void testBinaryTag() throws IOException {
+ byte[] binary = (byte[]) getMapValue("canonical: !<tag:yaml.org,2002:binary> " + content,
+ "canonical");
+ assertEquals((byte) 'G', binary[0]);
+ assertEquals((byte) 'I', binary[1]);
+ assertEquals((byte) 'F', binary[2]);
+ assertEquals((byte) '8', binary[3]);
+ assertEquals((byte) '9', binary[4]);
+ }
+
+ public void testBinaryOut() throws IOException {
+ byte[] data = "GIF89\tbi\u0003\u0000nary\n\u001Fimage\n".getBytes("ISO-8859-1");
+ Map<String, String> map = new HashMap<String, String>();
+ String value = new String(data, "ISO-8859-1");
+ map.put("canonical", value);
+ String output = dump(map);
+ assertEquals("canonical: !!binary |-\n R0lGODkJYmkDAG5hcnkKH2ltYWdlCg==\n", output);
+ }
+
+ public void testByteArray() throws IOException {
+ byte[] data = { 8, 14, 15, 10, 126, 32, 65, 65, 65 };
+ String output = dump(data);
+ assertEquals("!!binary |-\n CA4PCn4gQUFB\n", output);
+ byte[] parsed = (byte[]) load(output);
+ assertEquals(data.length, parsed.length);
+ for (int i = 0; i < data.length; i++) {
+ assertEquals(data[i], parsed[i]);
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/types/BoolTagTest.java b/src/test/java/org/yaml/snakeyaml/types/BoolTagTest.java
new file mode 100644
index 00000000..68a1cd08
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/types/BoolTagTest.java
@@ -0,0 +1,59 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.types;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @see http://yaml.org/type/int.html
+ */
+public class BoolTagTest extends AbstractTest {
+ public void testBool() throws IOException {
+ assertEquals(Boolean.TRUE, getMapValue("canonical: true", "canonical"));
+ assertEquals(Boolean.FALSE, getMapValue("answer: NO", "answer"));
+ assertEquals(Boolean.TRUE, getMapValue("logical: True", "logical"));
+ assertEquals(Boolean.TRUE, getMapValue("option: on", "option"));
+ }
+
+ public void testBoolCanonical() throws IOException {
+ assertEquals(Boolean.TRUE, getMapValue("canonical: Yes", "canonical"));
+ assertEquals(Boolean.TRUE, getMapValue("canonical: yes", "canonical"));
+ assertEquals(Boolean.TRUE, getMapValue("canonical: YES", "canonical"));
+ assertEquals("yES", getMapValue("canonical: yES", "canonical"));
+ assertEquals(Boolean.FALSE, getMapValue("canonical: No", "canonical"));
+ assertEquals(Boolean.FALSE, getMapValue("canonical: NO", "canonical"));
+ assertEquals(Boolean.FALSE, getMapValue("canonical: no", "canonical"));
+ assertEquals(Boolean.FALSE, getMapValue("canonical: off", "canonical"));
+ assertEquals(Boolean.FALSE, getMapValue("canonical: Off", "canonical"));
+ assertEquals(Boolean.FALSE, getMapValue("canonical: OFF", "canonical"));
+ assertEquals(Boolean.TRUE, getMapValue("canonical: ON", "canonical"));
+ assertEquals(Boolean.TRUE, getMapValue("canonical: On", "canonical"));
+ assertEquals(Boolean.TRUE, getMapValue("canonical: on", "canonical"));
+ // it looks like it is against the specification but it is like in
+ // PyYAML
+ assertEquals("n", getMapValue("canonical: n", "canonical"));
+ assertEquals("N", getMapValue("canonical: N", "canonical"));
+ assertEquals("y", getMapValue("canonical: y", "canonical"));
+ assertEquals("Y", getMapValue("canonical: Y", "canonical"));
+ }
+
+ public void testBoolShorthand() throws IOException {
+ assertEquals(Boolean.TRUE, getMapValue("boolean: !!bool true", "boolean"));
+ }
+
+ public void testBoolTag() throws IOException {
+ assertEquals(Boolean.TRUE,
+ getMapValue("boolean: !<tag:yaml.org,2002:bool> true", "boolean"));
+ }
+
+ public void testBoolOut() throws IOException {
+ Map<String, Boolean> map = new HashMap<String, Boolean>();
+ map.put("boolean", Boolean.TRUE);
+ String output = dump(map);
+ assertTrue(output, output.contains("boolean: true"));
+ }
+
+}
diff --git a/src/test/java/org/yaml/snakeyaml/types/FloatTagTest.java b/src/test/java/org/yaml/snakeyaml/types/FloatTagTest.java
new file mode 100644
index 00000000..aa3ede81
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/types/FloatTagTest.java
@@ -0,0 +1,55 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.types;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @see http://yaml.org/type/float.html
+ */
+public class FloatTagTest extends AbstractTest {
+
+ public void testFloat() throws IOException {
+ assertEquals(new Double(6.8523015e+5), getMapValue("canonical: 6.8523015e+5", "canonical"));
+ assertEquals(new Double(6.8523015e+5), getMapValue("exponentioal: 685.230_15e+03",
+ "exponentioal"));
+ assertEquals(new Double(6.8523015e+5), getMapValue("fixed: 685_230.15", "fixed"));
+ assertEquals(new Double(6.8523015e+5), getMapValue("sexagesimal: 190:20:30.15",
+ "sexagesimal"));
+ assertEquals(Double.NEGATIVE_INFINITY, getMapValue("negative infinity: -.inf",
+ "negative infinity"));
+ assertEquals(Double.NaN, getMapValue("not a number: .NaN", "not a number"));
+ }
+
+ public void testFloatShorthand() throws IOException {
+ assertEquals(new Double(1), getMapValue("number: !!float 1", "number"));
+ }
+
+ public void testFloatTag() throws IOException {
+ assertEquals(new Double(1), getMapValue("number: !<tag:yaml.org,2002:float> 1", "number"));
+ }
+
+ public void testFloatOut() throws IOException {
+ Map<String, Object> map = new HashMap<String, Object>();
+ map.put("number", new Double(1));
+ String output = dump(map);
+ assertEquals("{number: 1.0}\n", output);
+ }
+
+ public void testBasicDoubleScalarLoad() {
+ assertEquals(new Double(47.0), load("47.0"));
+ assertEquals(new Double(0.0), load("0.0"));
+ assertEquals(new Double(-1.0), load("-1.0"));
+ }
+
+ public void testDumpStr() {
+ assertEquals("'1.0'\n", dump("1.0"));
+ }
+
+ public void testDump() {
+ assertEquals("1.0\n", dump(1.0));
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/types/IntTagTest.java b/src/test/java/org/yaml/snakeyaml/types/IntTagTest.java
new file mode 100644
index 00000000..d75dad32
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/types/IntTagTest.java
@@ -0,0 +1,55 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.types;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @see http://yaml.org/type/int.html
+ */
+public class IntTagTest extends AbstractTest {
+
+ public void testInt() throws IOException {
+ assertEquals(new Integer(685230), getMapValue("canonical: 685230", "canonical"));
+ assertEquals(new Integer(685230), getMapValue("number: 685_230", "number"));
+ assertEquals(new Integer(685230), getMapValue("decimal: +685230", "decimal"));
+ assertEquals(new Integer(-685230), getMapValue("number: -685230", "number"));
+ assertEquals(new Integer(685230), getMapValue("octal: 02472256", "octal"));
+ assertEquals(new Integer(685230), getMapValue("hexadecimal: 0x_0A_74_AE", "hexadecimal"));
+ assertEquals(new Integer(685230), getMapValue("binary: 0b1010_0111_0100_1010_1110",
+ "binary"));
+ assertEquals(new Integer(685230), getMapValue("sexagesimal: 190:20:30", "sexagesimal"));
+ assertEquals(new Integer(0), load("0"));
+ assertEquals(new Integer(0), load("-0"));
+ assertEquals(new Integer(0), load("+0"));
+ assertEquals(Integer.MIN_VALUE, load(dump(Integer.MIN_VALUE)));
+ assertEquals(Integer.MAX_VALUE, load(dump(Integer.MAX_VALUE)));
+ }
+
+ public void testBigInt() throws IOException {
+ assertEquals(new Long(922337203685477580L), load("922337203685477580"));
+ assertEquals(new BigInteger("9223372036854775809999999999"),
+ load("9223372036854775809999999999"));
+ assertEquals(Long.MIN_VALUE, load("-9223372036854775808"));
+ }
+
+ public void testIntShorthand() throws IOException {
+ assertEquals(new Integer(1), getMapValue("number: !!int 1", "number"));
+ }
+
+ public void testIntTag() throws IOException {
+ assertEquals(new Integer(1), getMapValue("number: !<tag:yaml.org,2002:int> 1", "number"));
+ }
+
+ public void testIntOut() throws IOException {
+ Map<String, Integer> map = new HashMap<String, Integer>();
+ map.put("number", new Integer(1));
+ String output = dump(map);
+ assertTrue(output.contains("number: 1"));
+ }
+
+}
diff --git a/src/test/java/org/yaml/snakeyaml/types/MapTagTest.java b/src/test/java/org/yaml/snakeyaml/types/MapTagTest.java
new file mode 100644
index 00000000..5977c7e0
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/types/MapTagTest.java
@@ -0,0 +1,59 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.types;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.yaml.snakeyaml.YamlDocument;
+
+/**
+ * @see http://yaml.org/type/map.html
+ */
+public class MapTagTest extends AbstractTest {
+
+ @SuppressWarnings("unchecked")
+ public void testMap() throws IOException {
+ YamlDocument document = new YamlDocument("types/map.yaml");
+ Map<String, Map<String, String>> map = (Map<String, Map<String, String>>) document
+ .getNativeData();
+ assertEquals(2, map.size());
+ Map<String, String> map1 = (Map<String, String>) map.get("Block style");
+ assertEquals(3, map1.size());
+ assertEquals("Evans", map1.get("Clark"));
+ assertEquals("Ingerson", map1.get("Brian"));
+ assertEquals("Ben-Kiki", map1.get("Oren"));
+ //
+ Map<String, String> map2 = (Map<String, String>) map.get("Flow style");
+ assertEquals(3, map2.size());
+ assertEquals("Evans", map2.get("Clark"));
+ assertEquals("Ingerson", map2.get("Brian"));
+ assertEquals("Ben-Kiki", map2.get("Oren"));
+ //
+ assertEquals(map1, map2);
+ assertNotSame(map1, map2);
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testMapYaml11() throws IOException {
+ YamlDocument document = new YamlDocument("types/map_mixed_tags.yaml");
+ Map<String, Map<String, String>> map = (Map<String, Map<String, String>>) document
+ .getNativeData();
+ assertEquals(2, map.size());
+ Map<String, String> map1 = (Map<String, String>) map.get("Block style");
+ assertEquals(3, map1.size());
+ assertEquals("Evans", map1.get("Clark"));
+ assertEquals("Ingerson", map1.get("Brian"));
+ assertEquals("Ben-Kiki", map1.get("Oren"));
+ //
+ Map<String, String> map2 = (Map<String, String>) map.get("Flow style");
+ assertEquals(3, map2.size());
+ assertEquals("Evans", map2.get("Clark"));
+ assertEquals("Ingerson", map2.get("Brian"));
+ assertEquals("Ben-Kiki", map2.get("Oren"));
+ //
+ assertEquals(map1, map2);
+ }
+
+}
diff --git a/src/test/java/org/yaml/snakeyaml/types/MergeTagTest.java b/src/test/java/org/yaml/snakeyaml/types/MergeTagTest.java
new file mode 100644
index 00000000..1805d201
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/types/MergeTagTest.java
@@ -0,0 +1,59 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.types;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+import org.yaml.snakeyaml.YamlDocument;
+
+/**
+ * @see http://yaml.org/type/merge.html
+ */
+public class MergeTagTest extends AbstractTest {
+
+ @SuppressWarnings("unchecked")
+ public void testMerge() throws IOException {
+ YamlDocument document = new YamlDocument("types/merge.yaml");
+ List list = (List) document.getNativeData();
+ assertEquals(8, list.size());
+ Map<Object, Object> center = (Map<Object, Object>) list.get(0);
+ assertEquals(2, center.size());
+ assertEquals(new Integer(1), center.get("x"));
+ assertEquals(new Integer(2), center.get("y"));
+ //
+ Map<Object, Object> left = (Map<Object, Object>) list.get(1);
+ assertEquals(2, left.size());
+ assertEquals(left.get("x").getClass().toString(), new Integer(0), left.get("x"));
+ assertEquals(new Integer(2), left.get("y"));
+ //
+ Map<Object, Object> big = (Map<Object, Object>) list.get(2);
+ assertEquals(1, big.size());
+ assertEquals(new Integer(10), big.get("r"));
+ //
+ Map<Object, Object> small = (Map<Object, Object>) list.get(3);
+ assertEquals(1, small.size());
+ assertEquals(new Integer(1), small.get("r"));
+ // Explicit keys
+ Map<Object, Object> explicit = (Map<Object, Object>) list.get(4);
+ assertEquals(4, explicit.size());
+ assertEquals(new Integer(1), explicit.get("x"));
+ assertEquals(new Integer(2), explicit.get("y"));
+ assertEquals(new Integer(10), explicit.get("r"));
+ assertEquals("center/big", explicit.get("label"));
+ // Merge one map
+ Map<Object, Object> merged1 = (Map<Object, Object>) list.get(5);
+ assertEquals(explicit, merged1);
+ assertNotSame(explicit, merged1);
+ // Merge multiple maps
+ Map<Object, Object> merged2 = (Map<Object, Object>) list.get(6);
+ assertEquals(explicit, merged2);
+ assertNotSame(explicit, merged2);
+ // Override
+ Map<Object, Object> merged3 = (Map<Object, Object>) list.get(7);
+ assertEquals(explicit, merged3);
+ assertNotSame(explicit, merged3);
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/types/NullTagTest.java b/src/test/java/org/yaml/snakeyaml/types/NullTagTest.java
new file mode 100644
index 00000000..d874691e
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/types/NullTagTest.java
@@ -0,0 +1,73 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.types;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @see http://yaml.org/type/null.html
+ */
+public class NullTagTest extends AbstractTest {
+
+ public void testNull() throws IOException {
+ assertNull("Got: '" + load("---\n") + "'", load("---\n"));
+ assertNull(load("---\n..."));
+ assertNull(load("---\n...\n"));
+ assertNull(load("\n"));
+ assertNull(load(""));
+ assertNull(load(" "));
+ assertNull(load("~"));
+ assertNull(load("---\n~"));
+ assertNull(load("null"));
+ assertNull(load("Null"));
+ assertNull(load("NULL"));
+ assertNull(getMapValue("empty:\n", "empty"));
+ assertNull(getMapValue("canonical: ~", "canonical"));
+ assertNull(getMapValue("english: null", "english"));
+ assertNull(getMapValue("english: Null", "english"));
+ assertNull(getMapValue("english: NULL", "english"));
+ assertEquals("null key", getMapValue("~: null key\n", null));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testSequenceNull() throws IOException {
+ String input = "---\n# This sequence has five\n# entries, two have values.\nsparse:\n - ~\n - 2nd entry\n -\n - 4th entry\n - Null\n";
+ List<String> parsed = (List<String>) getMapValue(input, "sparse");
+ assertEquals(5, parsed.size());
+ assertNull(parsed.get(0));
+ assertEquals("2nd entry", parsed.get(1));
+ assertNull("Got: '" + parsed.get(2) + "'", parsed.get(2));
+ assertEquals("4th entry", parsed.get(3));
+ assertNull(parsed.get(4));
+ }
+
+ public void testNullInMap() throws IOException {
+ String input = "key1: null\n~: value1";
+ Map<String, Object> parsed = getMap(input);
+ assertEquals(2, parsed.size());
+ assertTrue(parsed.containsKey(null));
+ Object value1 = parsed.get(null);
+ assertEquals("value1", value1);
+ //
+ assertNull(parsed.get("key1"));
+ //
+ assertFalse(getMap("key2: value2").containsKey(null));
+ }
+
+ public void testBoolShorthand() throws IOException {
+ assertNull(getMapValue("nothing: !!null null", "nothing"));
+ }
+
+ public void testBoolTag() throws IOException {
+ assertNull(getMapValue("nothing: !<tag:yaml.org,2002:null> null", "nothing"));
+ }
+
+ public void testBoolOut() throws IOException {
+ String output = dump(null);
+ assertEquals("null\n", output);
+ }
+
+}
diff --git a/src/test/java/org/yaml/snakeyaml/types/OmapTagTest.java b/src/test/java/org/yaml/snakeyaml/types/OmapTagTest.java
new file mode 100644
index 00000000..4af21425
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/types/OmapTagTest.java
@@ -0,0 +1,35 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.types;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.yaml.snakeyaml.YamlDocument;
+
+/**
+ * @see http://yaml.org/type/omap.html
+ */
+public class OmapTagTest extends AbstractTest {
+
+ @SuppressWarnings("unchecked")
+ public void testOmap() throws IOException {
+ YamlDocument document = new YamlDocument("types/omap.yaml");
+ Map<String, Map<String, String>> map = (Map<String, Map<String, String>>) document
+ .getNativeData();
+ assertEquals(2, map.size());
+ Map<String, String> map1 = (Map<String, String>) map.get("Bestiary");
+ assertEquals(3, map1.size());
+ assertEquals("African pig-like ant eater. Ugly.", map1.get("aardvark"));
+ assertEquals("South-American ant eater. Two species.", map1.get("anteater"));
+ assertEquals("South-American constrictor snake. Scaly.", map1.get("anaconda"));
+ //
+ Map<String, String> map2 = (Map<String, String>) map.get("Numbers");
+ assertEquals(3, map2.size());
+ assertEquals(new Integer(1), map2.get("one"));
+ assertEquals(new Integer(2), map2.get("two"));
+ assertEquals(new Integer(3), map2.get("three"));
+ }
+
+}
diff --git a/src/test/java/org/yaml/snakeyaml/types/PairsTagTest.java b/src/test/java/org/yaml/snakeyaml/types/PairsTagTest.java
new file mode 100644
index 00000000..e03b3a6a
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/types/PairsTagTest.java
@@ -0,0 +1,59 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.types;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+import org.yaml.snakeyaml.YamlDocument;
+
+/**
+ * @see http://yaml.org/type/pairs.html
+ */
+public class PairsTagTest extends AbstractTest {
+
+ @SuppressWarnings("unchecked")
+ public void testPairs() throws IOException {
+ YamlDocument document = new YamlDocument("types/pairs.yaml", false);
+ Map<String, List<String[]>> map = (Map<String, List<String[]>>) document.getNativeData();
+ assertEquals(2, map.size());
+ List<String[]> list1 = (List<String[]>) map.get("Block tasks");
+ assertEquals(4, list1.size());
+ Object[] tuple1 = list1.get(0);
+ assertEquals(2, tuple1.length);
+ assertEquals("meeting", tuple1[0]);
+ assertEquals("with team.", tuple1[1]);
+ //
+
+ Object[] tuple2 = list1.get(1);
+ assertEquals(2, tuple2.length);
+ assertEquals("meeting", tuple2[0]);
+ assertEquals("with boss.", tuple2[1]);
+ //
+
+ Object[] tuple3 = list1.get(2);
+ assertEquals(2, tuple3.length);
+ assertEquals("break", tuple3[0]);
+ assertEquals("lunch.", tuple3[1]);
+ //
+
+ Object[] tuple4 = list1.get(3);
+ assertEquals(2, tuple4.length);
+ assertEquals("meeting", tuple4[0]);
+ assertEquals("with client.", tuple4[1]);
+ //
+ List<String[]> list2 = (List<String[]>) map.get("Flow tasks");
+ assertEquals(2, list2.size());
+ Object[] tuple2_1 = list2.get(0);
+ assertEquals(2, tuple2_1.length);
+ assertEquals("meeting", tuple2_1[0]);
+ assertEquals("with team", tuple2_1[1]);
+ //
+ Object[] tuple2_2 = list2.get(1);
+ assertEquals(2, tuple2_2.length);
+ assertEquals("meeting", tuple2_2[0]);
+ assertEquals("with boss", tuple2_2[1]);
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/types/SeqTagTest.java b/src/test/java/org/yaml/snakeyaml/types/SeqTagTest.java
new file mode 100644
index 00000000..0b142eed
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/types/SeqTagTest.java
@@ -0,0 +1,70 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.types;
+
+import java.util.List;
+import java.util.Map;
+
+import org.yaml.snakeyaml.YamlDocument;
+
+/**
+ * @see http://yaml.org/type/seq.html
+ */
+public class SeqTagTest extends AbstractTest {
+
+ @SuppressWarnings("unchecked")
+ public void testSeq() {
+ YamlDocument document = new YamlDocument("types/seq.yaml");
+ Map<String, List<String>> map = (Map<String, List<String>>) document.getNativeData();
+ assertEquals(2, map.size());
+ List<String> list1 = (List<String>) map.get("Block style");
+ assertEquals(9, list1.size());
+ assertEquals("Mercury", list1.get(0));
+ assertEquals("Venus", list1.get(1));
+ assertEquals("Earth", list1.get(2));
+ assertEquals("Mars", list1.get(3));
+ assertEquals("Jupiter", list1.get(4));
+ assertEquals("Saturn", list1.get(5));
+ assertEquals("Uranus", list1.get(6));
+ assertEquals("Neptune", list1.get(7));
+ assertEquals("Pluto", list1.get(8));
+ //
+ List<String> list2 = (List<String>) map.get("Flow style");
+ assertEquals(9, list2.size());
+ assertEquals("Mercury", list2.get(0));
+ assertEquals("Venus", list2.get(1));
+ assertEquals("Earth", list2.get(2));
+ assertEquals("Mars", list2.get(3));
+ assertEquals("Jupiter", list2.get(4));
+ assertEquals("Saturn", list2.get(5));
+ assertEquals("Uranus", list2.get(6));
+ assertEquals("Neptune", list2.get(7));
+ assertEquals("Pluto", list2.get(8));
+ //
+ assertEquals(list1, list2);
+ assertNotSame(list1, list2);
+ }
+
+ public void testArray() {
+ Integer[] array = new Integer[3];
+ array[0] = new Integer(1);
+ array[1] = new Integer(1);
+ array[2] = new Integer(2);
+ String output = dump(array);
+ assertEquals("[1, 1, 2]\n", output);
+ }
+
+ public void testArrayPrimitives() {
+ int[] array = new int[3];
+ array[0] = 1;
+ array[1] = 1;
+ array[2] = 2;
+ try {
+ dump(array);
+ fail("Arrays of primitives are not supported.");
+ } catch (RuntimeException e) {
+ assertEquals("Arrays of primitives are not fully supported.", e.getMessage());
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/types/SetTagTest.java b/src/test/java/org/yaml/snakeyaml/types/SetTagTest.java
new file mode 100644
index 00000000..ea0acbdc
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/types/SetTagTest.java
@@ -0,0 +1,33 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.types;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.yaml.snakeyaml.YamlDocument;
+
+/**
+ * @see http://yaml.org/type/set.html
+ */
+public class SetTagTest extends AbstractTest {
+
+ @SuppressWarnings("unchecked")
+ public void testSet() {
+ YamlDocument document = new YamlDocument("types/set.yaml");
+ Map<String, Set<String>> map = (Map<String, Set<String>>) document.getNativeData();
+ assertEquals(2, map.size());
+ Set<String> set1 = (Set<String>) map.get("baseball players");
+ assertEquals(3, set1.size());
+ assertTrue(set1.contains("Mark McGwire"));
+ assertTrue(set1.contains("Sammy Sosa"));
+ assertTrue(set1.contains("Ken Griffey"));
+ //
+ Set<String> set2 = (Set<String>) map.get("baseball teams");
+ assertEquals(3, set2.size());
+ assertTrue(set2.contains("Boston Red Sox"));
+ assertTrue(set2.contains("Detroit Tigers"));
+ assertTrue(set2.contains("New York Yankees"));
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/types/StrTagTest.java b/src/test/java/org/yaml/snakeyaml/types/StrTagTest.java
new file mode 100644
index 00000000..c2ebcd60
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/types/StrTagTest.java
@@ -0,0 +1,130 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.types;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.nio.charset.Charset;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.yaml.snakeyaml.Yaml;
+
+/**
+ * @see http://yaml.org/type/str.html
+ */
+public class StrTagTest extends AbstractTest {
+ private String getData(String data, String key) {
+ return (String) getMapValue(data, key);
+ }
+
+ public void testString() throws IOException {
+ assertEquals("abcd", getData("string: abcd", "string"));
+ }
+
+ public void testStringShorthand() throws IOException {
+ assertEquals("abcd", getData("string: !!str abcd", "string"));
+ }
+
+ public void testStringTag() throws IOException {
+ assertEquals("abcd", getData("string: !<tag:yaml.org,2002:str> abcd", "string"));
+ }
+
+ public void testUnicode() throws IOException {
+ // escaped 8-bit unicode character (u-umlaut):
+ assertEquals("\u00fc", load("\"\\xfc\""));
+ assertEquals("\\xfc", load("\\xfc"));
+
+ // 2 escaped 8-bit unicode characters (u-umlaut following by e-grave):
+ assertEquals("\u00fc\u00e8", load("\"\\xfc\\xe8\""));
+
+ // escaped 16-bit unicode character (em dash):
+ assertEquals("\u2014", load("\"\\u2014\""));
+
+ // UTF-32 encoding is explicitly not supported
+ assertEquals("\\U2014AAAA", load("'\\U2014AAAA'"));
+
+ // (and I don't have a surrogate pair handy at the moment)
+ // raw unicode characters in the stream (em dash)
+ assertEquals("\u2014", load("\u2014"));
+ }
+
+ /**
+ * @see http://code.google.com/p/jvyamlb/issues/detail?id=6
+ */
+ @SuppressWarnings("unchecked")
+ public void testIssueId6() {
+ Map<String, String> map = (Map<String, String>) load("---\ntest: |-\n \"Test\r\r (* error here)\"");
+ assertEquals("\"Test\n\n(* error here)\"", map.get("test"));
+ }
+
+ public void testStrDump() {
+ assertEquals("abc\n", dump("abc"));
+ }
+
+ public void testUnicodeDump() {
+ assertEquals("\\u263a\n", dump("\\u263a"));
+ assertEquals("The leading zero must be preserved.", "\\u063a\n", dump("\\u063a"));
+ }
+
+ public void testStringIntOut() {
+ Map<String, String> map = new HashMap<String, String>();
+ map.put("number", "1");
+ String output = dump(map);
+ assertTrue(output, output.contains("number: '1'"));
+ }
+
+ public void testStringFloatOut() {
+ Map<String, String> map = new HashMap<String, String>();
+ map.put("number", "1.1");
+ String output = dump(map);
+ assertTrue(output, output.contains("number: '1.1'"));
+ }
+
+ public void testStringBoolOut() {
+ Map<String, String> map = new HashMap<String, String>();
+ map.put("number", "True");
+ String output = dump(map);
+ assertTrue(output, output.contains("number: 'True'"));
+ }
+
+ public void testEmitLongString() throws IOException {
+ String str = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
+ String output = dump(str);
+ assertEquals(str + "\n", output);
+ }
+
+ public void testEmitLongStringWithCR() throws IOException {
+ String str = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n\n";
+ String output = dump(str);
+ assertEquals("'" + str + "\n '\n", output);
+ }
+
+ public void testEmitDoubleQuoted() throws IOException {
+ String str = "\"xx\"";
+ String output = dump(str);
+ assertEquals("'" + str + "'\n", output);
+ }
+
+ public void testEmitEndOfLine() throws IOException {
+ String str = "xxxxxxx\n";
+ String output = dump(str);
+ assertEquals("'" + str + "\n '\n", output);
+ }
+
+ public void testDumpUtf16() throws IOException {
+ String str = "xxx";
+ assertEquals(3, str.toString().length());
+ Yaml yaml = new Yaml();
+ Charset charset = Charset.forName("UTF-16");
+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ Writer writer = new OutputStreamWriter(stream, charset);
+ yaml.dump(str, writer);
+ assertEquals(str + "\n", stream.toString("UTF-16"));
+ assertEquals("Must include BOM: " + stream.toString(), (1 + 3 + 1) * 2, stream.toString()
+ .length());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/types/TimestampTagTest.java b/src/test/java/org/yaml/snakeyaml/types/TimestampTagTest.java
new file mode 100644
index 00000000..9135c046
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/types/TimestampTagTest.java
@@ -0,0 +1,93 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.types;
+
+import java.io.IOException;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.TimeZone;
+
+/**
+ * @see http://yaml.org/type/timestamp.html
+ */
+public class TimestampTagTest extends AbstractTest {
+
+ public void testTimestamp() throws IOException {
+ assertEquals("2001-12-15 at 2:59:43 (100)", getText("canonical: 2001-12-15T02:59:43.1Z",
+ "canonical"));
+ assertEquals("2001-12-15 at 2:59:43 (100)", getText(
+ "valid iso8601: 2001-12-14t21:59:43.10-05:00", "valid iso8601"));
+ assertEquals("2001-12-15 at 2:59:43 (100)", getText(
+ "space separated: 2001-12-14 21:59:43.10 -5", "space separated"));
+ assertEquals("2001-12-15 at 2:59:43 (100)", getText(
+ "no time zone (Z): 2001-12-15 2:59:43.10", "no time zone (Z)"));
+ assertEquals("2002-12-14 at 0:0:0 (0)", getText("date (00:00:00Z): 2002-12-14",
+ "date (00:00:00Z)"));
+ }
+
+ public void testTimestampShorthand() throws IOException {
+ assertTrue(getMapValue("canonical: !!timestamp 2001-12-15T02:59:43.1Z", "canonical") instanceof Date);
+ }
+
+ public void testTimestampTag() throws IOException {
+ assertTrue(getMapValue("canonical: !<tag:yaml.org,2002:timestamp> 2001-12-15T02:59:43.1Z",
+ "canonical") instanceof Date);
+ }
+
+ public void testTimestampOut() throws IOException {
+ Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("Europe/Moscow"));
+ cal.clear();
+ cal.set(2008, 8, 23, 14, 35, 4);
+ Date date = cal.getTime();
+ String output = dump(date);
+ assertEquals("2008-09-23T10:35:04Z\n", output);
+ }
+
+ public void testTimestampOutMap() throws IOException {
+ Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("Europe/Moscow"));
+ cal.clear();
+ cal.set(2008, 8, 23, 14, 35, 4);
+ Date date = cal.getTime();
+ Map<String, Date> map = new HashMap<String, Date>();
+ map.put("canonical", date);
+ String output = dump(map);
+ assertEquals("{canonical: !!timestamp '2008-09-23T10:35:04Z'}\n", output);
+ }
+
+ private String getText(String yaml, String key) {
+ Date date = (Date) getMapValue(yaml, key);
+ Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
+ cal.setTime(date);
+ int years = cal.get(Calendar.YEAR);
+ int months = cal.get(Calendar.MONTH) + 1; // 0..12
+ int days = cal.get(Calendar.DAY_OF_MONTH); // 1..31
+ int hour24 = cal.get(Calendar.HOUR_OF_DAY); // 0..24
+ int minutes = cal.get(Calendar.MINUTE); // 0..59
+ int seconds = cal.get(Calendar.SECOND); // 0..59
+ int millis = cal.get(Calendar.MILLISECOND);
+ String result = String.valueOf(years) + "-" + String.valueOf(months) + "-"
+ + String.valueOf(days) + " at " + String.valueOf(hour24) + ":"
+ + String.valueOf(minutes) + ":" + String.valueOf(seconds) + " ("
+ + String.valueOf(millis) + ")";
+ return result;
+ }
+
+ public void testTimestampReadWrite() throws IOException {
+ Date date = (Date) getMapValue("Time: 2001-11-23 15:01:42 -5", "Time");
+ Map<String, Date> map = new HashMap<String, Date>();
+ map.put("canonical", date);
+ String output = dump(map);
+ assertEquals("{canonical: !!timestamp '2001-11-23T20:01:42Z'}\n", output);
+ }
+
+ public void testSqlDate() throws IOException {
+ java.sql.Date date = new java.sql.Date(1000000000000L);
+ Map<String, java.sql.Date> map = new HashMap<String, java.sql.Date>();
+ map.put("canonical", date);
+ String output = dump(map);
+ assertEquals("{canonical: !!timestamp '2001-09-09T01:46:40Z'}\n", output);
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/types/ValueTagTest.java b/src/test/java/org/yaml/snakeyaml/types/ValueTagTest.java
new file mode 100644
index 00000000..a18a2e02
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/types/ValueTagTest.java
@@ -0,0 +1,49 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.types;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.YamlDocument;
+
+/**
+ * @see http://yaml.org/type/value.html
+ */
+public class ValueTagTest extends AbstractTest {
+
+ /**
+ * The 'value' tag does not work as defined in the specification but exactly
+ * as in PyYAML
+ */
+ @SuppressWarnings("unchecked")
+ public void testValue() throws IOException {
+ InputStream input = YamlDocument.class.getClassLoader().getResourceAsStream(
+ YamlDocument.ROOT + "types/value.yaml");
+ Yaml yaml = new Yaml();
+ Iterator iter = (Iterator) yaml.loadAll(input).iterator();
+ Map<String, List<String>> oldSchema = (Map<String, List<String>>) iter.next();
+ assertEquals(1, oldSchema.size());
+ List<String> list = oldSchema.get("link with");
+ assertEquals(2, list.size());
+ assertEquals("library1.dll", list.get(0));
+ assertEquals("library2.dll", list.get(1));
+ //
+ Map<String, List<Map<String, String>>> newSchema = (Map<String, List<Map<String, String>>>) iter
+ .next();
+ assertEquals(1, newSchema.size());
+ //
+ List<Map<String, String>> list2 = newSchema.get("link with");
+ assertEquals(2, list2.size());
+ Map<String, String> map1 = list2.get(0);
+ assertEquals(2, map1.size());
+ assertEquals("library1.dll", map1.get("="));
+ assertEquals(new Double(1.2), map1.get("version"));
+ assertFalse(iter.hasNext());
+ }
+}
diff --git a/src/test/resources/constructor/car-no-root-class-map.yaml b/src/test/resources/constructor/car-no-root-class-map.yaml
new file mode 100644
index 00000000..a2b9f317
--- /dev/null
+++ b/src/test/resources/constructor/car-no-root-class-map.yaml
@@ -0,0 +1,15 @@
+plate: 00-FF-Q2
+wheels:
+ ? {brand: Pirelli, id: 1}
+ : 2008-01-16
+ ? {brand: Dunkel, id: 2}
+ : 2002-12-24
+ ? {brand: Pirelli, id: 3}
+ : 2008-01-16
+ ? {brand: Pirelli, id: 4}
+ : 2008-01-16
+ ? {brand: Pirelli, id: 5}
+ : 2008-01-16
+windows:
+ front: 0
+ back: 1 \ No newline at end of file
diff --git a/src/test/resources/constructor/car-no-root-class.yaml b/src/test/resources/constructor/car-no-root-class.yaml
new file mode 100644
index 00000000..a6451940
--- /dev/null
+++ b/src/test/resources/constructor/car-no-root-class.yaml
@@ -0,0 +1,8 @@
+# No root class defined
+plate: 12-XP-F4
+wheels:
+- {id: 1}
+- {id: 2}
+- {id: 3}
+- {id: 4}
+- {id: 5} \ No newline at end of file
diff --git a/src/test/resources/constructor/car-with-tags.yaml b/src/test/resources/constructor/car-with-tags.yaml
new file mode 100644
index 00000000..2f7e823f
--- /dev/null
+++ b/src/test/resources/constructor/car-with-tags.yaml
@@ -0,0 +1,8 @@
+!!org.yaml.snakeyaml.constructor.Car
+plate: 12-XP-F4
+wheels:
+- {id: 1}
+- {id: 2}
+- {id: 3}
+- {id: 4}
+- {id: 5} \ No newline at end of file
diff --git a/src/test/resources/constructor/car-without-root-tag.yaml b/src/test/resources/constructor/car-without-root-tag.yaml
new file mode 100644
index 00000000..b91b184f
--- /dev/null
+++ b/src/test/resources/constructor/car-without-root-tag.yaml
@@ -0,0 +1,5 @@
+map: {id: 3}
+part: null
+plate: 12-XP-F4
+wheel: {id: 2}
+year: '2008' \ No newline at end of file
diff --git a/src/test/resources/constructor/car-without-tags.yaml b/src/test/resources/constructor/car-without-tags.yaml
new file mode 100644
index 00000000..20f5556a
--- /dev/null
+++ b/src/test/resources/constructor/car-without-tags.yaml
@@ -0,0 +1,8 @@
+!car
+plate: 12-XP-F4
+wheels:
+- {id: 1}
+- {id: 2}
+- {id: 3}
+- {id: 4}
+- {id: 5} \ No newline at end of file
diff --git a/src/test/resources/constructor/cararray-with-tags.yaml b/src/test/resources/constructor/cararray-with-tags.yaml
new file mode 100644
index 00000000..fed7cda5
--- /dev/null
+++ b/src/test/resources/constructor/cararray-with-tags.yaml
@@ -0,0 +1,8 @@
+!!org.yaml.snakeyaml.constructor.ArrayTagsTest$CarWithArray
+plate: 12-XP-F4
+wheels:
+- {id: 1}
+- {id: 2}
+- {id: 3}
+- {id: 4}
+- {id: 5} \ No newline at end of file
diff --git a/src/test/resources/constructor/carwheel-root-map.yaml b/src/test/resources/constructor/carwheel-root-map.yaml
new file mode 100644
index 00000000..d7ea8857
--- /dev/null
+++ b/src/test/resources/constructor/carwheel-root-map.yaml
@@ -0,0 +1,3 @@
+wheel: !!org.yaml.snakeyaml.constructor.Wheel {id: 2}
+map: {id: 3}
+plate: 12-XP-F4
diff --git a/src/test/resources/constructor/carwheel-without-tags.yaml b/src/test/resources/constructor/carwheel-without-tags.yaml
new file mode 100644
index 00000000..ab0ac449
--- /dev/null
+++ b/src/test/resources/constructor/carwheel-without-tags.yaml
@@ -0,0 +1,6 @@
+!!org.yaml.snakeyaml.constructor.ImplicitTagsTest$CarWithWheel
+map: {id: 3}
+part: !!org.yaml.snakeyaml.constructor.Wheel {id: 4}
+plate: 12-XP-F4
+wheel: {id: 2}
+year: '2008'
diff --git a/src/test/resources/constructor/test-primitives1.yaml b/src/test/resources/constructor/test-primitives1.yaml
new file mode 100644
index 00000000..7403c37d
--- /dev/null
+++ b/src/test/resources/constructor/test-primitives1.yaml
@@ -0,0 +1,23 @@
+# TestBean1
+byteClass: 1
+bytePrimitive: -3
+shortClass: +0
+shortPrimitive: -015 # octal
+integer: 5
+intPrimitive: 17
+text: the text
+id: 13
+longClass: 11111111111
+longPrimitive: 9999999999
+booleanClass: True
+booleanPrimitive: on
+charClass: 2
+charPrimitive: '#'
+bigInteger: 1234567890123456789012345678901234567890
+floatClass: 2
+floatPrimitive: 3.1416
+doubleClass: 4.0
+doublePrimitive: +1.12e4
+date: 2008-01-09
+publicField: public
+
diff --git a/src/test/resources/examples/any-object-example.yaml b/src/test/resources/examples/any-object-example.yaml
new file mode 100644
index 00000000..2ba2be54
--- /dev/null
+++ b/src/test/resources/examples/any-object-example.yaml
@@ -0,0 +1,6 @@
+none: [~, null]
+bool: [true, false, on, off]
+int: 42
+float: 3.14159
+list: [LITE, RES_ACID, SUS_DEXT]
+dict: {hp: 13, sp: 5}
diff --git a/src/test/resources/examples/spring.xml b/src/test/resources/examples/spring.xml
new file mode 100644
index 00000000..3d9a30c8
--- /dev/null
+++ b/src/test/resources/examples/spring.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:util="http://www.springframework.org/schema/util" xmlns:p="http://www.springframework.org/schema/p"
+ xsi:schemaLocation="
+http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
+http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.0.xsd">
+
+ <!-- the most powerful way -->
+ <bean id="yamlConstructor" class="examples.CustomConstructor" scope="prototype" />
+ <bean id="yamlLoader" class="org.yaml.snakeyaml.Loader" scope="prototype">
+ <constructor-arg ref="yamlConstructor" />
+ </bean>
+ <bean id="yamlRepresenter" class="org.yaml.snakeyaml.representer.Representer" scope="prototype" />
+ <bean id="yamlOptions" class="org.yaml.snakeyaml.DumperOptions" scope="prototype">
+ <property name="indent" value="2" />
+ </bean>
+ <bean id="yamlDumper" class="org.yaml.snakeyaml.Dumper" scope="prototype">
+ <constructor-arg ref="yamlRepresenter" />
+ <constructor-arg ref="yamlOptions" />
+ </bean>
+ <bean id="snakeYaml" class="org.yaml.snakeyaml.Yaml" scope="prototype">
+ <constructor-arg ref="yamlLoader" />
+ <constructor-arg ref="yamlDumper" />
+ </bean>
+
+ <!-- for a single JavaBean -->
+ <bean id="beanConstructor" class="org.yaml.snakeyaml.constructor.Constructor" scope="prototype">
+ <constructor-arg value="org.yaml.snakeyaml.Invoice" />
+ </bean>
+ <bean id="beanLoader" class="org.yaml.snakeyaml.Loader" scope="prototype">
+ <constructor-arg ref="beanConstructor" />
+ </bean>
+ <bean id="javabeanYaml" class="org.yaml.snakeyaml.Yaml" scope="prototype">
+ <constructor-arg ref="beanLoader" />
+ </bean>
+
+ <!-- the simplest way -->
+ <bean id="standardYaml" class="org.yaml.snakeyaml.Yaml" scope="prototype" />
+</beans> \ No newline at end of file
diff --git a/src/test/resources/pyyaml/a-nasty-libyaml-bug.loader-error b/src/test/resources/pyyaml/a-nasty-libyaml-bug.loader-error
new file mode 100644
index 00000000..f97d49f8
--- /dev/null
+++ b/src/test/resources/pyyaml/a-nasty-libyaml-bug.loader-error
@@ -0,0 +1 @@
+[ [ \ No newline at end of file
diff --git a/src/test/resources/pyyaml/aliases.events b/src/test/resources/pyyaml/aliases.events
new file mode 100644
index 00000000..9139b515
--- /dev/null
+++ b/src/test/resources/pyyaml/aliases.events
@@ -0,0 +1,8 @@
+- !StreamStart
+- !DocumentStart
+- !SequenceStart
+- !Scalar { anchor: 'myanchor', tag: '!mytag', value: 'data' }
+- !Alias { anchor: 'myanchor' }
+- !SequenceEnd
+- !DocumentEnd
+- !StreamEnd
diff --git a/src/test/resources/pyyaml/bool.data b/src/test/resources/pyyaml/bool.data
new file mode 100644
index 00000000..0988b631
--- /dev/null
+++ b/src/test/resources/pyyaml/bool.data
@@ -0,0 +1,4 @@
+- yes
+- NO
+- True
+- on
diff --git a/src/test/resources/pyyaml/colon-in-flow-context.loader-error b/src/test/resources/pyyaml/colon-in-flow-context.loader-error
new file mode 100644
index 00000000..13d50875
--- /dev/null
+++ b/src/test/resources/pyyaml/colon-in-flow-context.loader-error
@@ -0,0 +1 @@
+{ foo:bar }
diff --git a/src/test/resources/pyyaml/construct-binary.data b/src/test/resources/pyyaml/construct-binary.data
new file mode 100644
index 00000000..dcdb16f3
--- /dev/null
+++ b/src/test/resources/pyyaml/construct-binary.data
@@ -0,0 +1,12 @@
+canonical: !!binary "\
+ R0lGODlhDAAMAIQAAP//9/X17unp5WZmZgAAAOfn515eXvPz7Y6OjuDg4J+fn5\
+ OTk6enp56enmlpaWNjY6Ojo4SEhP/++f/++f/++f/++f/++f/++f/++f/++f/+\
+ +f/++f/++f/++f/++f/++SH+Dk1hZGUgd2l0aCBHSU1QACwAAAAADAAMAAAFLC\
+ AgjoEwnuNAFOhpEMTRiggcz4BNJHrv/zCFcLiwMWYNG84BwwEeECcgggoBADs="
+generic: !!binary |
+ R0lGODlhDAAMAIQAAP//9/X17unp5WZmZgAAAOfn515eXvPz7Y6OjuDg4J+fn5
+ OTk6enp56enmlpaWNjY6Ojo4SEhP/++f/++f/++f/++f/++f/++f/++f/++f/+
+ +f/++f/++f/++f/++f/++SH+Dk1hZGUgd2l0aCBHSU1QACwAAAAADAAMAAAFLC
+ AgjoEwnuNAFOhpEMTRiggcz4BNJHrv/zCFcLiwMWYNG84BwwEeECcgggoBADs=
+description:
+ The binary value above is a tiny arrow encoded as a gif image.
diff --git a/src/test/resources/pyyaml/construct-bool.data b/src/test/resources/pyyaml/construct-bool.data
new file mode 100644
index 00000000..36d6519b
--- /dev/null
+++ b/src/test/resources/pyyaml/construct-bool.data
@@ -0,0 +1,9 @@
+canonical: yes
+answer: NO
+logical: True
+option: on
+
+
+but:
+ y: is a string
+ n: is a string
diff --git a/src/test/resources/pyyaml/construct-custom.data b/src/test/resources/pyyaml/construct-custom.data
new file mode 100644
index 00000000..9db0f644
--- /dev/null
+++ b/src/test/resources/pyyaml/construct-custom.data
@@ -0,0 +1,26 @@
+---
+- !tag1
+ x: 1
+- !tag1
+ x: 1
+ 'y': 2
+ z: 3
+- !tag2
+ 10
+- !tag2
+ =: 10
+ 'y': 20
+ z: 30
+- !tag3
+ x: 1
+- !tag3
+ x: 1
+ 'y': 2
+ z: 3
+- !tag3
+ =: 1
+ 'y': 2
+ z: 3
+- !foo
+ my-parameter: foo
+ my-another-parameter: [1,2,3]
diff --git a/src/test/resources/pyyaml/construct-float.data b/src/test/resources/pyyaml/construct-float.data
new file mode 100644
index 00000000..b662c623
--- /dev/null
+++ b/src/test/resources/pyyaml/construct-float.data
@@ -0,0 +1,6 @@
+canonical: 6.8523015e+5
+exponential: 685.230_15e+03
+fixed: 685_230.15
+sexagesimal: 190:20:30.15
+negative infinity: -.inf
+not a number: .NaN
diff --git a/src/test/resources/pyyaml/construct-int.data b/src/test/resources/pyyaml/construct-int.data
new file mode 100644
index 00000000..852c3148
--- /dev/null
+++ b/src/test/resources/pyyaml/construct-int.data
@@ -0,0 +1,6 @@
+canonical: 685230
+decimal: +685_230
+octal: 02472256
+hexadecimal: 0x_0A_74_AE
+binary: 0b1010_0111_0100_1010_1110
+sexagesimal: 190:20:30
diff --git a/src/test/resources/pyyaml/construct-map.data b/src/test/resources/pyyaml/construct-map.data
new file mode 100644
index 00000000..022446df
--- /dev/null
+++ b/src/test/resources/pyyaml/construct-map.data
@@ -0,0 +1,6 @@
+# Unordered set of key: value pairs.
+Block style: !!map
+ Clark : Evans
+ Brian : Ingerson
+ Oren : Ben-Kiki
+Flow style: !!map { Clark: Evans, Brian: Ingerson, Oren: Ben-Kiki }
diff --git a/src/test/resources/pyyaml/construct-merge.data b/src/test/resources/pyyaml/construct-merge.data
new file mode 100644
index 00000000..3fdb2e20
--- /dev/null
+++ b/src/test/resources/pyyaml/construct-merge.data
@@ -0,0 +1,27 @@
+---
+- &CENTER { x: 1, 'y': 2 }
+- &LEFT { x: 0, 'y': 2 }
+- &BIG { r: 10 }
+- &SMALL { r: 1 }
+
+# All the following maps are equal:
+
+- # Explicit keys
+ x: 1
+ 'y': 2
+ r: 10
+ label: center/big
+
+- # Merge one map
+ << : *CENTER
+ r: 10
+ label: center/big
+
+- # Merge multiple maps
+ << : [ *CENTER, *BIG ]
+ label: center/big
+
+- # Override
+ << : [ *BIG, *LEFT, *SMALL ]
+ x: 1
+ label: center/big
diff --git a/src/test/resources/pyyaml/construct-null.data b/src/test/resources/pyyaml/construct-null.data
new file mode 100644
index 00000000..9ad0344c
--- /dev/null
+++ b/src/test/resources/pyyaml/construct-null.data
@@ -0,0 +1,18 @@
+# A document may be null.
+---
+---
+# This mapping has four keys,
+# one has a value.
+empty:
+canonical: ~
+english: null
+~: null key
+---
+# This sequence has five
+# entries, two have values.
+sparse:
+ - ~
+ - 2nd entry
+ -
+ - 4th entry
+ - Null
diff --git a/src/test/resources/pyyaml/construct-omap.data b/src/test/resources/pyyaml/construct-omap.data
new file mode 100644
index 00000000..4fa0f45f
--- /dev/null
+++ b/src/test/resources/pyyaml/construct-omap.data
@@ -0,0 +1,8 @@
+# Explicitly typed ordered map (dictionary).
+Bestiary: !!omap
+ - aardvark: African pig-like ant eater. Ugly.
+ - anteater: South-American ant eater. Two species.
+ - anaconda: South-American constrictor snake. Scaly.
+ # Etc.
+# Flow style
+Numbers: !!omap [ one: 1, two: 2, three : 3 ]
diff --git a/src/test/resources/pyyaml/construct-pairs.data b/src/test/resources/pyyaml/construct-pairs.data
new file mode 100644
index 00000000..05f55b94
--- /dev/null
+++ b/src/test/resources/pyyaml/construct-pairs.data
@@ -0,0 +1,7 @@
+# Explicitly typed pairs.
+Block tasks: !!pairs
+ - meeting: with team.
+ - meeting: with boss.
+ - break: lunch.
+ - meeting: with client.
+Flow tasks: !!pairs [ meeting: with team, meeting: with boss ]
diff --git a/src/test/resources/pyyaml/construct-seq.data b/src/test/resources/pyyaml/construct-seq.data
new file mode 100644
index 00000000..bb92fd11
--- /dev/null
+++ b/src/test/resources/pyyaml/construct-seq.data
@@ -0,0 +1,15 @@
+# Ordered sequence of nodes
+Block style: !!seq
+- Mercury # Rotates - no light/dark sides.
+- Venus # Deadliest. Aptly named.
+- Earth # Mostly dirt.
+- Mars # Seems empty.
+- Jupiter # The king.
+- Saturn # Pretty.
+- Uranus # Where the sun hardly shines.
+- Neptune # Boring. No rings.
+- Pluto # You call this a planet?
+Flow style: !!seq [ Mercury, Venus, Earth, Mars, # Rocks
+ Jupiter, Saturn, Uranus, Neptune, # Gas
+ Pluto ] # Overrated
+
diff --git a/src/test/resources/pyyaml/construct-set.data b/src/test/resources/pyyaml/construct-set.data
new file mode 100644
index 00000000..e05dc885
--- /dev/null
+++ b/src/test/resources/pyyaml/construct-set.data
@@ -0,0 +1,7 @@
+# Explicitly typed set.
+baseball players: !!set
+ ? Mark McGwire
+ ? Sammy Sosa
+ ? Ken Griffey
+# Flow style
+baseball teams: !!set { Boston Red Sox, Detroit Tigers, New York Yankees }
diff --git a/src/test/resources/pyyaml/construct-str-ascii.data b/src/test/resources/pyyaml/construct-str-ascii.data
new file mode 100644
index 00000000..0d93013b
--- /dev/null
+++ b/src/test/resources/pyyaml/construct-str-ascii.data
@@ -0,0 +1 @@
+--- !!str "ascii string"
diff --git a/src/test/resources/pyyaml/construct-str-utf8.data b/src/test/resources/pyyaml/construct-str-utf8.data
new file mode 100644
index 00000000..e355f184
--- /dev/null
+++ b/src/test/resources/pyyaml/construct-str-utf8.data
@@ -0,0 +1 @@
+--- !!str "Это уникодная строка"
diff --git a/src/test/resources/pyyaml/construct-str.data b/src/test/resources/pyyaml/construct-str.data
new file mode 100644
index 00000000..606ac6b2
--- /dev/null
+++ b/src/test/resources/pyyaml/construct-str.data
@@ -0,0 +1 @@
+string: abcd
diff --git a/src/test/resources/pyyaml/construct-timestamp.data b/src/test/resources/pyyaml/construct-timestamp.data
new file mode 100644
index 00000000..c5f3840b
--- /dev/null
+++ b/src/test/resources/pyyaml/construct-timestamp.data
@@ -0,0 +1,5 @@
+canonical: 2001-12-15T02:59:43.1Z
+valid iso8601: 2001-12-14t21:59:43.10-05:00
+space separated: 2001-12-14 21:59:43.10 -5
+no time zone (Z): 2001-12-15 2:59:43.10
+date (00:00:00Z): 2002-12-14
diff --git a/src/test/resources/pyyaml/construct-value.data b/src/test/resources/pyyaml/construct-value.data
new file mode 100644
index 00000000..3eb79198
--- /dev/null
+++ b/src/test/resources/pyyaml/construct-value.data
@@ -0,0 +1,10 @@
+--- # Old schema
+link with:
+ - library1.dll
+ - library2.dll
+--- # New schema
+link with:
+ - = : library1.dll
+ version: 1.2
+ - = : library2.dll
+ version: 2.3
diff --git a/src/test/resources/pyyaml/document-separator-in-quoted-scalar.loader-error b/src/test/resources/pyyaml/document-separator-in-quoted-scalar.loader-error
new file mode 100644
index 00000000..9eeb0d6f
--- /dev/null
+++ b/src/test/resources/pyyaml/document-separator-in-quoted-scalar.loader-error
@@ -0,0 +1,11 @@
+---
+"this --- is correct"
+---
+"this
+...is also
+correct"
+---
+"a quoted scalar
+cannot contain
+---
+document separators"
diff --git a/src/test/resources/pyyaml/documents.events b/src/test/resources/pyyaml/documents.events
new file mode 100644
index 00000000..775a51a7
--- /dev/null
+++ b/src/test/resources/pyyaml/documents.events
@@ -0,0 +1,11 @@
+- !StreamStart
+- !DocumentStart { explicit: false }
+- !Scalar { implicit: [true,false], value: 'data' }
+- !DocumentEnd
+- !DocumentStart
+- !Scalar { implicit: [true,false] }
+- !DocumentEnd
+- !DocumentStart { version: [1,1], tags: { '!': '!foo', '!yaml!': 'tag:yaml.org,2002:', '!ugly!': '!!!!!!!' } }
+- !Scalar { implicit: [true,false] }
+- !DocumentEnd
+- !StreamEnd
diff --git a/src/test/resources/pyyaml/duplicate-anchor-1.loader-error b/src/test/resources/pyyaml/duplicate-anchor-1.loader-error
new file mode 100644
index 00000000..906cf29d
--- /dev/null
+++ b/src/test/resources/pyyaml/duplicate-anchor-1.loader-error
@@ -0,0 +1,3 @@
+- &foo bar
+- &bar bar
+- &foo bar
diff --git a/src/test/resources/pyyaml/duplicate-anchor-2.loader-error b/src/test/resources/pyyaml/duplicate-anchor-2.loader-error
new file mode 100644
index 00000000..62b43897
--- /dev/null
+++ b/src/test/resources/pyyaml/duplicate-anchor-2.loader-error
@@ -0,0 +1 @@
+&foo [1, 2, 3, &foo 4]
diff --git a/src/test/resources/pyyaml/duplicate-key.former-loader-error.data b/src/test/resources/pyyaml/duplicate-key.former-loader-error.data
new file mode 100644
index 00000000..84deb8f2
--- /dev/null
+++ b/src/test/resources/pyyaml/duplicate-key.former-loader-error.data
@@ -0,0 +1,3 @@
+---
+foo: bar
+foo: baz
diff --git a/src/test/resources/pyyaml/duplicate-mapping-key.former-loader-error.data b/src/test/resources/pyyaml/duplicate-mapping-key.former-loader-error.data
new file mode 100644
index 00000000..7e7b4d13
--- /dev/null
+++ b/src/test/resources/pyyaml/duplicate-mapping-key.former-loader-error.data
@@ -0,0 +1,6 @@
+---
+&anchor foo:
+ foo: bar
+ *anchor: duplicate key
+ baz: bat
+ *anchor: duplicate key
diff --git a/src/test/resources/pyyaml/duplicate-merge-key.former-loader-error.data b/src/test/resources/pyyaml/duplicate-merge-key.former-loader-error.data
new file mode 100644
index 00000000..cebc3a18
--- /dev/null
+++ b/src/test/resources/pyyaml/duplicate-merge-key.former-loader-error.data
@@ -0,0 +1,4 @@
+---
+<<: {x: 1, y: 2}
+foo: bar
+<<: {z: 3, t: 4}
diff --git a/src/test/resources/pyyaml/duplicate-tag-directive.loader-error b/src/test/resources/pyyaml/duplicate-tag-directive.loader-error
new file mode 100644
index 00000000..50c81a06
--- /dev/null
+++ b/src/test/resources/pyyaml/duplicate-tag-directive.loader-error
@@ -0,0 +1,3 @@
+%TAG !foo! bar
+%TAG !foo! baz
+--- foo
diff --git a/src/test/resources/pyyaml/duplicate-value-key.former-loader-error.data b/src/test/resources/pyyaml/duplicate-value-key.former-loader-error.data
new file mode 100644
index 00000000..b34a1d69
--- /dev/null
+++ b/src/test/resources/pyyaml/duplicate-value-key.former-loader-error.data
@@ -0,0 +1,4 @@
+---
+=: 1
+foo: bar
+=: 2
diff --git a/src/test/resources/pyyaml/duplicate-yaml-directive.loader-error b/src/test/resources/pyyaml/duplicate-yaml-directive.loader-error
new file mode 100644
index 00000000..9b723905
--- /dev/null
+++ b/src/test/resources/pyyaml/duplicate-yaml-directive.loader-error
@@ -0,0 +1,3 @@
+%YAML 1.1
+%YAML 1.1
+--- foo
diff --git a/src/test/resources/pyyaml/emit-block-scalar-in-simple-key-context-bug.canonical b/src/test/resources/pyyaml/emit-block-scalar-in-simple-key-context-bug.canonical
new file mode 100644
index 00000000..473bed5d
--- /dev/null
+++ b/src/test/resources/pyyaml/emit-block-scalar-in-simple-key-context-bug.canonical
@@ -0,0 +1,6 @@
+%YAML 1.1
+--- !!map
+{
+ ? !!str "foo"
+ : !!str "bar"
+}
diff --git a/src/test/resources/pyyaml/emit-block-scalar-in-simple-key-context-bug.data b/src/test/resources/pyyaml/emit-block-scalar-in-simple-key-context-bug.data
new file mode 100644
index 00000000..b6b42ba5
--- /dev/null
+++ b/src/test/resources/pyyaml/emit-block-scalar-in-simple-key-context-bug.data
@@ -0,0 +1,4 @@
+? |-
+ foo
+: |-
+ bar
diff --git a/src/test/resources/pyyaml/emitting-unacceptable-unicode-character-bug.data b/src/test/resources/pyyaml/emitting-unacceptable-unicode-character-bug.data
new file mode 100644
index 00000000..2a5df00d
--- /dev/null
+++ b/src/test/resources/pyyaml/emitting-unacceptable-unicode-character-bug.data
@@ -0,0 +1 @@
+"\udd00"
diff --git a/src/test/resources/pyyaml/empty-anchor.emitter-error b/src/test/resources/pyyaml/empty-anchor.emitter-error
new file mode 100644
index 00000000..ce663b63
--- /dev/null
+++ b/src/test/resources/pyyaml/empty-anchor.emitter-error
@@ -0,0 +1,5 @@
+- !StreamStart
+- !DocumentStart
+- !Scalar { anchor: '', value: 'foo' }
+- !DocumentEnd
+- !StreamEnd
diff --git a/src/test/resources/pyyaml/empty-document-bug.canonical b/src/test/resources/pyyaml/empty-document-bug.canonical
new file mode 100644
index 00000000..28a6cf13
--- /dev/null
+++ b/src/test/resources/pyyaml/empty-document-bug.canonical
@@ -0,0 +1 @@
+# This YAML stream contains no YAML documents.
diff --git a/src/test/resources/pyyaml/empty-document-bug.data b/src/test/resources/pyyaml/empty-document-bug.data
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/test/resources/pyyaml/empty-document-bug.data
diff --git a/src/test/resources/pyyaml/empty-documents.single-loader-error b/src/test/resources/pyyaml/empty-documents.single-loader-error
new file mode 100644
index 00000000..f8dba8d4
--- /dev/null
+++ b/src/test/resources/pyyaml/empty-documents.single-loader-error
@@ -0,0 +1,2 @@
+--- # first document
+--- # second document
diff --git a/src/test/resources/pyyaml/empty-tag-handle.emitter-error b/src/test/resources/pyyaml/empty-tag-handle.emitter-error
new file mode 100644
index 00000000..235c8998
--- /dev/null
+++ b/src/test/resources/pyyaml/empty-tag-handle.emitter-error
@@ -0,0 +1,5 @@
+- !StreamStart
+- !DocumentStart { tags: { '': 'bar' } }
+- !Scalar { value: 'foo' }
+- !DocumentEnd
+- !StreamEnd
diff --git a/src/test/resources/pyyaml/empty-tag-prefix.emitter-error b/src/test/resources/pyyaml/empty-tag-prefix.emitter-error
new file mode 100644
index 00000000..c6c0e955
--- /dev/null
+++ b/src/test/resources/pyyaml/empty-tag-prefix.emitter-error
@@ -0,0 +1,5 @@
+- !StreamStart
+- !DocumentStart { tags: { '!': '' } }
+- !Scalar { value: 'foo' }
+- !DocumentEnd
+- !StreamEnd
diff --git a/src/test/resources/pyyaml/empty-tag.emitter-error b/src/test/resources/pyyaml/empty-tag.emitter-error
new file mode 100644
index 00000000..b7ca5931
--- /dev/null
+++ b/src/test/resources/pyyaml/empty-tag.emitter-error
@@ -0,0 +1,5 @@
+- !StreamStart
+- !DocumentStart
+- !Scalar { tag: '', value: 'key', implicit: [false,false] }
+- !DocumentEnd
+- !StreamEnd
diff --git a/src/test/resources/pyyaml/expected-document-end.emitter-error b/src/test/resources/pyyaml/expected-document-end.emitter-error
new file mode 100644
index 00000000..0cbab899
--- /dev/null
+++ b/src/test/resources/pyyaml/expected-document-end.emitter-error
@@ -0,0 +1,6 @@
+- !StreamStart
+- !DocumentStart
+- !Scalar { value: 'data 1' }
+- !Scalar { value: 'data 2' }
+- !DocumentEnd
+- !StreamEnd
diff --git a/src/test/resources/pyyaml/expected-document-start.emitter-error b/src/test/resources/pyyaml/expected-document-start.emitter-error
new file mode 100644
index 00000000..8ce575ec
--- /dev/null
+++ b/src/test/resources/pyyaml/expected-document-start.emitter-error
@@ -0,0 +1,4 @@
+- !StreamStart
+- !MappingStart
+- !MappingEnd
+- !StreamEnd
diff --git a/src/test/resources/pyyaml/expected-mapping.loader-error b/src/test/resources/pyyaml/expected-mapping.loader-error
new file mode 100644
index 00000000..82aed98a
--- /dev/null
+++ b/src/test/resources/pyyaml/expected-mapping.loader-error
@@ -0,0 +1 @@
+--- !!map [not, a, map]
diff --git a/src/test/resources/pyyaml/expected-node-1.emitter-error b/src/test/resources/pyyaml/expected-node-1.emitter-error
new file mode 100644
index 00000000..36ceca3e
--- /dev/null
+++ b/src/test/resources/pyyaml/expected-node-1.emitter-error
@@ -0,0 +1,4 @@
+- !StreamStart
+- !DocumentStart
+- !DocumentEnd
+- !StreamEnd
diff --git a/src/test/resources/pyyaml/expected-node-2.emitter-error b/src/test/resources/pyyaml/expected-node-2.emitter-error
new file mode 100644
index 00000000..891ee370
--- /dev/null
+++ b/src/test/resources/pyyaml/expected-node-2.emitter-error
@@ -0,0 +1,7 @@
+- !StreamStart
+- !DocumentStart
+- !MappingStart
+- !Scalar { value: 'key' }
+- !MappingEnd
+- !DocumentEnd
+- !StreamEnd
diff --git a/src/test/resources/pyyaml/expected-nothing.emitter-error b/src/test/resources/pyyaml/expected-nothing.emitter-error
new file mode 100644
index 00000000..62c54d3e
--- /dev/null
+++ b/src/test/resources/pyyaml/expected-nothing.emitter-error
@@ -0,0 +1,4 @@
+- !StreamStart
+- !StreamEnd
+- !StreamStart
+- !StreamEnd
diff --git a/src/test/resources/pyyaml/expected-scalar.loader-error b/src/test/resources/pyyaml/expected-scalar.loader-error
new file mode 100644
index 00000000..7b3171e8
--- /dev/null
+++ b/src/test/resources/pyyaml/expected-scalar.loader-error
@@ -0,0 +1 @@
+--- !!str [not a scalar]
diff --git a/src/test/resources/pyyaml/expected-sequence.loader-error b/src/test/resources/pyyaml/expected-sequence.loader-error
new file mode 100644
index 00000000..08074ea5
--- /dev/null
+++ b/src/test/resources/pyyaml/expected-sequence.loader-error
@@ -0,0 +1 @@
+--- !!seq {foo, bar, baz}
diff --git a/src/test/resources/pyyaml/expected-stream-start.emitter-error b/src/test/resources/pyyaml/expected-stream-start.emitter-error
new file mode 100644
index 00000000..480dc2eb
--- /dev/null
+++ b/src/test/resources/pyyaml/expected-stream-start.emitter-error
@@ -0,0 +1,2 @@
+- !DocumentStart
+- !DocumentEnd
diff --git a/src/test/resources/pyyaml/explicit-document.single-loader-error b/src/test/resources/pyyaml/explicit-document.single-loader-error
new file mode 100644
index 00000000..46c6f8b7
--- /dev/null
+++ b/src/test/resources/pyyaml/explicit-document.single-loader-error
@@ -0,0 +1,4 @@
+---
+foo: bar
+---
+foo: bar
diff --git a/src/test/resources/pyyaml/fetch-complex-value-bug.loader-error b/src/test/resources/pyyaml/fetch-complex-value-bug.loader-error
new file mode 100644
index 00000000..25fac24e
--- /dev/null
+++ b/src/test/resources/pyyaml/fetch-complex-value-bug.loader-error
@@ -0,0 +1,2 @@
+? "foo"
+ : "bar"
diff --git a/src/test/resources/pyyaml/float-representer-2.3-bug.data b/src/test/resources/pyyaml/float-representer-2.3-bug.data
new file mode 100644
index 00000000..efd17163
--- /dev/null
+++ b/src/test/resources/pyyaml/float-representer-2.3-bug.data
@@ -0,0 +1,5 @@
+#0.0: # hash(0) == hash(nan) and 0 == nan in Python 2.3
+1.0: 1
++.inf: 10
+-.inf: -10
+.nan: 100
diff --git a/src/test/resources/pyyaml/float.data b/src/test/resources/pyyaml/float.data
new file mode 100644
index 00000000..524d5db3
--- /dev/null
+++ b/src/test/resources/pyyaml/float.data
@@ -0,0 +1,6 @@
+- 6.8523015e+5
+- 685.230_15e+03
+- 685_230.15
+- 190:20:30.15
+- -.inf
+- .NaN
diff --git a/src/test/resources/pyyaml/forbidden-entry.loader-error b/src/test/resources/pyyaml/forbidden-entry.loader-error
new file mode 100644
index 00000000..f2e30796
--- /dev/null
+++ b/src/test/resources/pyyaml/forbidden-entry.loader-error
@@ -0,0 +1,2 @@
+test: - foo
+ - bar
diff --git a/src/test/resources/pyyaml/forbidden-key.loader-error b/src/test/resources/pyyaml/forbidden-key.loader-error
new file mode 100644
index 00000000..da9b471d
--- /dev/null
+++ b/src/test/resources/pyyaml/forbidden-key.loader-error
@@ -0,0 +1,2 @@
+test: ? foo
+ : bar
diff --git a/src/test/resources/pyyaml/forbidden-value.loader-error b/src/test/resources/pyyaml/forbidden-value.loader-error
new file mode 100644
index 00000000..efd7ce58
--- /dev/null
+++ b/src/test/resources/pyyaml/forbidden-value.loader-error
@@ -0,0 +1 @@
+test: key: value
diff --git a/src/test/resources/pyyaml/implicit-document.single-loader-error b/src/test/resources/pyyaml/implicit-document.single-loader-error
new file mode 100644
index 00000000..f8c9a5c6
--- /dev/null
+++ b/src/test/resources/pyyaml/implicit-document.single-loader-error
@@ -0,0 +1,3 @@
+foo: bar
+---
+foo: bar
diff --git a/src/test/resources/pyyaml/int.data b/src/test/resources/pyyaml/int.data
new file mode 100644
index 00000000..d44d3761
--- /dev/null
+++ b/src/test/resources/pyyaml/int.data
@@ -0,0 +1,6 @@
+- 685230
+- +685_230
+- 02472256
+- 0x_0A_74_AE
+- 0b1010_0111_0100_1010_1110
+- 190:20:30
diff --git a/src/test/resources/pyyaml/invalid-anchor-1.loader-error b/src/test/resources/pyyaml/invalid-anchor-1.loader-error
new file mode 100644
index 00000000..fcf7d0f6
--- /dev/null
+++ b/src/test/resources/pyyaml/invalid-anchor-1.loader-error
@@ -0,0 +1 @@
+--- &? foo # we allow only ascii and numeric characters in anchor names.
diff --git a/src/test/resources/pyyaml/invalid-anchor-2.loader-error b/src/test/resources/pyyaml/invalid-anchor-2.loader-error
new file mode 100644
index 00000000..bfc4ff01
--- /dev/null
+++ b/src/test/resources/pyyaml/invalid-anchor-2.loader-error
@@ -0,0 +1,8 @@
+---
+- [
+ &correct foo,
+ *correct,
+ *correct] # still correct
+- *correct: still correct
+- &correct-or-not[foo, bar]
+
diff --git a/src/test/resources/pyyaml/invalid-anchor.emitter-error b/src/test/resources/pyyaml/invalid-anchor.emitter-error
new file mode 100644
index 00000000..3d2a8148
--- /dev/null
+++ b/src/test/resources/pyyaml/invalid-anchor.emitter-error
@@ -0,0 +1,5 @@
+- !StreamStart
+- !DocumentStart
+- !Scalar { anchor: '5*5=25', value: 'foo' }
+- !DocumentEnd
+- !StreamEnd
diff --git a/src/test/resources/pyyaml/invalid-base64-data.loader-error b/src/test/resources/pyyaml/invalid-base64-data.loader-error
new file mode 100644
index 00000000..798abbae
--- /dev/null
+++ b/src/test/resources/pyyaml/invalid-base64-data.loader-error
@@ -0,0 +1,2 @@
+--- !!binary
+ binary data encoded in base64 should be here.
diff --git a/src/test/resources/pyyaml/invalid-block-scalar-indicator.loader-error b/src/test/resources/pyyaml/invalid-block-scalar-indicator.loader-error
new file mode 100644
index 00000000..16a6db18
--- /dev/null
+++ b/src/test/resources/pyyaml/invalid-block-scalar-indicator.loader-error
@@ -0,0 +1,2 @@
+--- > what is this? # a comment
+data
diff --git a/src/test/resources/pyyaml/invalid-character.loader-error b/src/test/resources/pyyaml/invalid-character.loader-error
new file mode 100644
index 00000000..03687b02
--- /dev/null
+++ b/src/test/resources/pyyaml/invalid-character.loader-error
Binary files differ
diff --git a/src/test/resources/pyyaml/invalid-character.stream-error b/src/test/resources/pyyaml/invalid-character.stream-error
new file mode 100644
index 00000000..03687b02
--- /dev/null
+++ b/src/test/resources/pyyaml/invalid-character.stream-error
Binary files differ
diff --git a/src/test/resources/pyyaml/invalid-directive-line.loader-error b/src/test/resources/pyyaml/invalid-directive-line.loader-error
new file mode 100644
index 00000000..0892eb66
--- /dev/null
+++ b/src/test/resources/pyyaml/invalid-directive-line.loader-error
@@ -0,0 +1,2 @@
+%YAML 1.1 ? # extra symbol
+---
diff --git a/src/test/resources/pyyaml/invalid-directive-name-1.loader-error b/src/test/resources/pyyaml/invalid-directive-name-1.loader-error
new file mode 100644
index 00000000..153fd889
--- /dev/null
+++ b/src/test/resources/pyyaml/invalid-directive-name-1.loader-error
@@ -0,0 +1,2 @@
+% # no name at all
+---
diff --git a/src/test/resources/pyyaml/invalid-directive-name-2.loader-error b/src/test/resources/pyyaml/invalid-directive-name-2.loader-error
new file mode 100644
index 00000000..3732a06a
--- /dev/null
+++ b/src/test/resources/pyyaml/invalid-directive-name-2.loader-error
@@ -0,0 +1,2 @@
+%invalid-characters:in-directive name
+---
diff --git a/src/test/resources/pyyaml/invalid-escape-character.loader-error b/src/test/resources/pyyaml/invalid-escape-character.loader-error
new file mode 100644
index 00000000..a95ab767
--- /dev/null
+++ b/src/test/resources/pyyaml/invalid-escape-character.loader-error
@@ -0,0 +1 @@
+"some escape characters are \ncorrect, but this one \?\nis not\n"
diff --git a/src/test/resources/pyyaml/invalid-escape-numbers.loader-error b/src/test/resources/pyyaml/invalid-escape-numbers.loader-error
new file mode 100644
index 00000000..614ec9f5
--- /dev/null
+++ b/src/test/resources/pyyaml/invalid-escape-numbers.loader-error
@@ -0,0 +1 @@
+"hm.... \u123?"
diff --git a/src/test/resources/pyyaml/invalid-indentation-indicator-1.loader-error b/src/test/resources/pyyaml/invalid-indentation-indicator-1.loader-error
new file mode 100644
index 00000000..a3cd12f5
--- /dev/null
+++ b/src/test/resources/pyyaml/invalid-indentation-indicator-1.loader-error
@@ -0,0 +1,2 @@
+--- >0 # not valid
+data
diff --git a/src/test/resources/pyyaml/invalid-indentation-indicator-2.loader-error b/src/test/resources/pyyaml/invalid-indentation-indicator-2.loader-error
new file mode 100644
index 00000000..eefb6ecd
--- /dev/null
+++ b/src/test/resources/pyyaml/invalid-indentation-indicator-2.loader-error
@@ -0,0 +1,2 @@
+--- >-0
+data
diff --git a/src/test/resources/pyyaml/invalid-merge-1.loader-error b/src/test/resources/pyyaml/invalid-merge-1.loader-error
new file mode 100644
index 00000000..fc3c2844
--- /dev/null
+++ b/src/test/resources/pyyaml/invalid-merge-1.loader-error
@@ -0,0 +1,2 @@
+foo: bar
+<<: baz
diff --git a/src/test/resources/pyyaml/invalid-merge-2.loader-error b/src/test/resources/pyyaml/invalid-merge-2.loader-error
new file mode 100644
index 00000000..8e88615c
--- /dev/null
+++ b/src/test/resources/pyyaml/invalid-merge-2.loader-error
@@ -0,0 +1,2 @@
+foo: bar
+<<: [x: 1, y: 2, z, t: 4]
diff --git a/src/test/resources/pyyaml/invalid-omap-1.loader-error b/src/test/resources/pyyaml/invalid-omap-1.loader-error
new file mode 100644
index 00000000..28633926
--- /dev/null
+++ b/src/test/resources/pyyaml/invalid-omap-1.loader-error
@@ -0,0 +1,3 @@
+--- !!omap
+foo: bar
+baz: bat
diff --git a/src/test/resources/pyyaml/invalid-omap-2.loader-error b/src/test/resources/pyyaml/invalid-omap-2.loader-error
new file mode 100644
index 00000000..c377dfb8
--- /dev/null
+++ b/src/test/resources/pyyaml/invalid-omap-2.loader-error
@@ -0,0 +1,3 @@
+--- !!omap
+- foo: bar
+- baz
diff --git a/src/test/resources/pyyaml/invalid-omap-3.loader-error b/src/test/resources/pyyaml/invalid-omap-3.loader-error
new file mode 100644
index 00000000..2a4f50d9
--- /dev/null
+++ b/src/test/resources/pyyaml/invalid-omap-3.loader-error
@@ -0,0 +1,4 @@
+--- !!omap
+- foo: bar
+- baz: bar
+ bar: bar
diff --git a/src/test/resources/pyyaml/invalid-pairs-1.loader-error b/src/test/resources/pyyaml/invalid-pairs-1.loader-error
new file mode 100644
index 00000000..42d19aec
--- /dev/null
+++ b/src/test/resources/pyyaml/invalid-pairs-1.loader-error
@@ -0,0 +1,3 @@
+--- !!pairs
+foo: bar
+baz: bat
diff --git a/src/test/resources/pyyaml/invalid-pairs-2.loader-error b/src/test/resources/pyyaml/invalid-pairs-2.loader-error
new file mode 100644
index 00000000..31389eae
--- /dev/null
+++ b/src/test/resources/pyyaml/invalid-pairs-2.loader-error
@@ -0,0 +1,3 @@
+--- !!pairs
+- foo: bar
+- baz
diff --git a/src/test/resources/pyyaml/invalid-pairs-3.loader-error b/src/test/resources/pyyaml/invalid-pairs-3.loader-error
new file mode 100644
index 00000000..f8d7704e
--- /dev/null
+++ b/src/test/resources/pyyaml/invalid-pairs-3.loader-error
@@ -0,0 +1,4 @@
+--- !!pairs
+- foo: bar
+- baz: bar
+ bar: bar
diff --git a/src/test/resources/pyyaml/invalid-simple-key.loader-error b/src/test/resources/pyyaml/invalid-simple-key.loader-error
new file mode 100644
index 00000000..a58deecf
--- /dev/null
+++ b/src/test/resources/pyyaml/invalid-simple-key.loader-error
@@ -0,0 +1,3 @@
+key: value
+invalid simple key
+next key: next value
diff --git a/src/test/resources/pyyaml/invalid-single-quote-bug.data b/src/test/resources/pyyaml/invalid-single-quote-bug.data
new file mode 100644
index 00000000..76ef7ae3
--- /dev/null
+++ b/src/test/resources/pyyaml/invalid-single-quote-bug.data
@@ -0,0 +1,2 @@
+- "foo 'bar'"
+- "foo\n'bar'"
diff --git a/src/test/resources/pyyaml/invalid-starting-character.loader-error b/src/test/resources/pyyaml/invalid-starting-character.loader-error
new file mode 100644
index 00000000..bb81c60c
--- /dev/null
+++ b/src/test/resources/pyyaml/invalid-starting-character.loader-error
@@ -0,0 +1 @@
+@@@@@@@@@@@@@@@@@@@
diff --git a/src/test/resources/pyyaml/invalid-tag-1.loader-error b/src/test/resources/pyyaml/invalid-tag-1.loader-error
new file mode 100644
index 00000000..a68cd384
--- /dev/null
+++ b/src/test/resources/pyyaml/invalid-tag-1.loader-error
@@ -0,0 +1 @@
+- !<foo#bar> baz
diff --git a/src/test/resources/pyyaml/invalid-tag-2.loader-error b/src/test/resources/pyyaml/invalid-tag-2.loader-error
new file mode 100644
index 00000000..3a36700a
--- /dev/null
+++ b/src/test/resources/pyyaml/invalid-tag-2.loader-error
@@ -0,0 +1 @@
+- !prefix!foo#bar baz
diff --git a/src/test/resources/pyyaml/invalid-tag-directive-handle.loader-error b/src/test/resources/pyyaml/invalid-tag-directive-handle.loader-error
new file mode 100644
index 00000000..42b5d7e9
--- /dev/null
+++ b/src/test/resources/pyyaml/invalid-tag-directive-handle.loader-error
@@ -0,0 +1,2 @@
+%TAG !!! !!!
+---
diff --git a/src/test/resources/pyyaml/invalid-tag-directive-prefix.loader-error b/src/test/resources/pyyaml/invalid-tag-directive-prefix.loader-error
new file mode 100644
index 00000000..0cb482c9
--- /dev/null
+++ b/src/test/resources/pyyaml/invalid-tag-directive-prefix.loader-error
@@ -0,0 +1,2 @@
+%TAG ! tag:zz.com/foo#bar # '#' is not allowed in URLs
+---
diff --git a/src/test/resources/pyyaml/invalid-tag-handle-1.emitter-error b/src/test/resources/pyyaml/invalid-tag-handle-1.emitter-error
new file mode 100644
index 00000000..d5df9a26
--- /dev/null
+++ b/src/test/resources/pyyaml/invalid-tag-handle-1.emitter-error
@@ -0,0 +1,5 @@
+- !StreamStart
+- !DocumentStart { tags: { '!foo': 'bar' } }
+- !Scalar { value: 'foo' }
+- !DocumentEnd
+- !StreamEnd
diff --git a/src/test/resources/pyyaml/invalid-tag-handle-1.loader-error b/src/test/resources/pyyaml/invalid-tag-handle-1.loader-error
new file mode 100644
index 00000000..ef0d1430
--- /dev/null
+++ b/src/test/resources/pyyaml/invalid-tag-handle-1.loader-error
@@ -0,0 +1,2 @@
+%TAG foo bar
+---
diff --git a/src/test/resources/pyyaml/invalid-tag-handle-2.emitter-error b/src/test/resources/pyyaml/invalid-tag-handle-2.emitter-error
new file mode 100644
index 00000000..d1831d55
--- /dev/null
+++ b/src/test/resources/pyyaml/invalid-tag-handle-2.emitter-error
@@ -0,0 +1,5 @@
+- !StreamStart
+- !DocumentStart { tags: { '!!!': 'bar' } }
+- !Scalar { value: 'foo' }
+- !DocumentEnd
+- !StreamEnd
diff --git a/src/test/resources/pyyaml/invalid-tag-handle-2.loader-error b/src/test/resources/pyyaml/invalid-tag-handle-2.loader-error
new file mode 100644
index 00000000..06c7f0e4
--- /dev/null
+++ b/src/test/resources/pyyaml/invalid-tag-handle-2.loader-error
@@ -0,0 +1,2 @@
+%TAG !foo bar
+---
diff --git a/src/test/resources/pyyaml/invalid-uri-escapes-1.loader-error b/src/test/resources/pyyaml/invalid-uri-escapes-1.loader-error
new file mode 100644
index 00000000..a6ecb36a
--- /dev/null
+++ b/src/test/resources/pyyaml/invalid-uri-escapes-1.loader-error
@@ -0,0 +1 @@
+--- !<tag:%x?y> foo
diff --git a/src/test/resources/pyyaml/invalid-uri-escapes-2.loader-error b/src/test/resources/pyyaml/invalid-uri-escapes-2.loader-error
new file mode 100644
index 00000000..b89e8f6a
--- /dev/null
+++ b/src/test/resources/pyyaml/invalid-uri-escapes-2.loader-error
@@ -0,0 +1 @@
+--- !<%FF> foo
diff --git a/src/test/resources/pyyaml/invalid-uri-escapes-3.loader-error b/src/test/resources/pyyaml/invalid-uri-escapes-3.loader-error
new file mode 100644
index 00000000..f2e4cb82
--- /dev/null
+++ b/src/test/resources/pyyaml/invalid-uri-escapes-3.loader-error
@@ -0,0 +1 @@
+--- !<foo%d0%af%d0%af%d0bar> baz
diff --git a/src/test/resources/pyyaml/invalid-uri.loader-error b/src/test/resources/pyyaml/invalid-uri.loader-error
new file mode 100644
index 00000000..06307e06
--- /dev/null
+++ b/src/test/resources/pyyaml/invalid-uri.loader-error
@@ -0,0 +1 @@
+--- !foo! bar
diff --git a/src/test/resources/pyyaml/invalid-utf8-byte.loader-error b/src/test/resources/pyyaml/invalid-utf8-byte.loader-error
new file mode 100644
index 00000000..15111c3e
--- /dev/null
+++ b/src/test/resources/pyyaml/invalid-utf8-byte.loader-error
@@ -0,0 +1,18 @@
+-------------------------------------------------------------------------------------------------------------------------------
+-------------------------------------------------------------------------------------------------------------------------------
+-------------------------------------------------------------------------------------------------------------------------------
+-------------------------------------------------------------------------------------------------------------------------------
+-------------------------------------------------------------------------------------------------------------------------------
+-------------------------------------------------------------------------------------------------------------------------------
+-------------------------------------------------------------------------------------------------------------------------------
+-------------------------------------------------------------------------------------------------------------------------------
+-------------------------------------------------------------------------------------------------------------------------------
+-------------------------------------------------------------------------------------------------------------------------------
+-------------------------------------------------------------------------------------------------------------------------------
+-------------------------------------------------------------------------------------------------------------------------------
+-------------------------------------------------------------------------------------------------------------------------------
+-------------------------------------------------------------------------------------------------------------------------------
+-------------------------------------------------------------------------------------------------------------------------------
+-------------------------------------------------------------------------------------------------------------------------------
+Invalid byte ('\xFF'): <--
+-------------------------------------------------------------------------------------------------------------------------------
diff --git a/src/test/resources/pyyaml/invalid-utf8-byte.stream-error b/src/test/resources/pyyaml/invalid-utf8-byte.stream-error
new file mode 100644
index 00000000..15111c3e
--- /dev/null
+++ b/src/test/resources/pyyaml/invalid-utf8-byte.stream-error
@@ -0,0 +1,18 @@
+-------------------------------------------------------------------------------------------------------------------------------
+-------------------------------------------------------------------------------------------------------------------------------
+-------------------------------------------------------------------------------------------------------------------------------
+-------------------------------------------------------------------------------------------------------------------------------
+-------------------------------------------------------------------------------------------------------------------------------
+-------------------------------------------------------------------------------------------------------------------------------
+-------------------------------------------------------------------------------------------------------------------------------
+-------------------------------------------------------------------------------------------------------------------------------
+-------------------------------------------------------------------------------------------------------------------------------
+-------------------------------------------------------------------------------------------------------------------------------
+-------------------------------------------------------------------------------------------------------------------------------
+-------------------------------------------------------------------------------------------------------------------------------
+-------------------------------------------------------------------------------------------------------------------------------
+-------------------------------------------------------------------------------------------------------------------------------
+-------------------------------------------------------------------------------------------------------------------------------
+-------------------------------------------------------------------------------------------------------------------------------
+Invalid byte ('\xFF'): <--
+-------------------------------------------------------------------------------------------------------------------------------
diff --git a/src/test/resources/pyyaml/invalid-yaml-directive-version-1.loader-error b/src/test/resources/pyyaml/invalid-yaml-directive-version-1.loader-error
new file mode 100644
index 00000000..e9b4e3a6
--- /dev/null
+++ b/src/test/resources/pyyaml/invalid-yaml-directive-version-1.loader-error
@@ -0,0 +1,3 @@
+# No version at all.
+%YAML
+---
diff --git a/src/test/resources/pyyaml/invalid-yaml-directive-version-2.loader-error b/src/test/resources/pyyaml/invalid-yaml-directive-version-2.loader-error
new file mode 100644
index 00000000..6aa7740e
--- /dev/null
+++ b/src/test/resources/pyyaml/invalid-yaml-directive-version-2.loader-error
@@ -0,0 +1,2 @@
+%YAML 1e-5
+---
diff --git a/src/test/resources/pyyaml/invalid-yaml-directive-version-3.loader-error b/src/test/resources/pyyaml/invalid-yaml-directive-version-3.loader-error
new file mode 100644
index 00000000..345e7842
--- /dev/null
+++ b/src/test/resources/pyyaml/invalid-yaml-directive-version-3.loader-error
@@ -0,0 +1,2 @@
+%YAML 1.
+---
diff --git a/src/test/resources/pyyaml/invalid-yaml-directive-version-4.loader-error b/src/test/resources/pyyaml/invalid-yaml-directive-version-4.loader-error
new file mode 100644
index 00000000..b35ca820
--- /dev/null
+++ b/src/test/resources/pyyaml/invalid-yaml-directive-version-4.loader-error
@@ -0,0 +1,2 @@
+%YAML 1.132.435
+---
diff --git a/src/test/resources/pyyaml/invalid-yaml-directive-version-5.loader-error b/src/test/resources/pyyaml/invalid-yaml-directive-version-5.loader-error
new file mode 100644
index 00000000..7c2b49f5
--- /dev/null
+++ b/src/test/resources/pyyaml/invalid-yaml-directive-version-5.loader-error
@@ -0,0 +1,2 @@
+%YAML A.0
+---
diff --git a/src/test/resources/pyyaml/invalid-yaml-directive-version-6.loader-error b/src/test/resources/pyyaml/invalid-yaml-directive-version-6.loader-error
new file mode 100644
index 00000000..bae714fc
--- /dev/null
+++ b/src/test/resources/pyyaml/invalid-yaml-directive-version-6.loader-error
@@ -0,0 +1,2 @@
+%YAML 123.C
+---
diff --git a/src/test/resources/pyyaml/invalid-yaml-version.loader-error b/src/test/resources/pyyaml/invalid-yaml-version.loader-error
new file mode 100644
index 00000000..dd019488
--- /dev/null
+++ b/src/test/resources/pyyaml/invalid-yaml-version.loader-error
@@ -0,0 +1,2 @@
+%YAML 2.0
+--- foo
diff --git a/src/test/resources/pyyaml/mappings.events b/src/test/resources/pyyaml/mappings.events
new file mode 100644
index 00000000..3cb5579f
--- /dev/null
+++ b/src/test/resources/pyyaml/mappings.events
@@ -0,0 +1,44 @@
+- !StreamStart
+
+- !DocumentStart
+- !MappingStart
+- !Scalar { implicit: [true,true], value: 'key' }
+- !Scalar { implicit: [true,true], value: 'value' }
+- !Scalar { implicit: [true,true], value: 'empty mapping' }
+- !MappingStart
+- !MappingEnd
+- !Scalar { implicit: [true,true], value: 'empty mapping with tag' }
+- !MappingStart { tag: '!mytag', implicit: false }
+- !MappingEnd
+- !Scalar { implicit: [true,true], value: 'block mapping' }
+- !MappingStart
+- !MappingStart
+- !Scalar { implicit: [true,true], value: 'complex' }
+- !Scalar { implicit: [true,true], value: 'key' }
+- !Scalar { implicit: [true,true], value: 'complex' }
+- !Scalar { implicit: [true,true], value: 'key' }
+- !MappingEnd
+- !MappingStart
+- !Scalar { implicit: [true,true], value: 'complex' }
+- !Scalar { implicit: [true,true], value: 'key' }
+- !MappingEnd
+- !MappingEnd
+- !Scalar { implicit: [true,true], value: 'flow mapping' }
+- !MappingStart { flow_style: true }
+- !Scalar { implicit: [true,true], value: 'key' }
+- !Scalar { implicit: [true,true], value: 'value' }
+- !MappingStart
+- !Scalar { implicit: [true,true], value: 'complex' }
+- !Scalar { implicit: [true,true], value: 'key' }
+- !Scalar { implicit: [true,true], value: 'complex' }
+- !Scalar { implicit: [true,true], value: 'key' }
+- !MappingEnd
+- !MappingStart
+- !Scalar { implicit: [true,true], value: 'complex' }
+- !Scalar { implicit: [true,true], value: 'key' }
+- !MappingEnd
+- !MappingEnd
+- !MappingEnd
+- !DocumentEnd
+
+- !StreamEnd
diff --git a/src/test/resources/pyyaml/merge.data b/src/test/resources/pyyaml/merge.data
new file mode 100644
index 00000000..e455bbcd
--- /dev/null
+++ b/src/test/resources/pyyaml/merge.data
@@ -0,0 +1 @@
+- <<
diff --git a/src/test/resources/pyyaml/more-floats.data b/src/test/resources/pyyaml/more-floats.data
new file mode 100644
index 00000000..399eb177
--- /dev/null
+++ b/src/test/resources/pyyaml/more-floats.data
@@ -0,0 +1 @@
+[0.0, +1.0, -1.0, +.inf, -.inf, .nan, .nan]
diff --git a/src/test/resources/pyyaml/negative-float-bug.data b/src/test/resources/pyyaml/negative-float-bug.data
new file mode 100644
index 00000000..18e16e38
--- /dev/null
+++ b/src/test/resources/pyyaml/negative-float-bug.data
@@ -0,0 +1 @@
+-1.0
diff --git a/src/test/resources/pyyaml/no-alias-anchor.emitter-error b/src/test/resources/pyyaml/no-alias-anchor.emitter-error
new file mode 100644
index 00000000..5ff065c1
--- /dev/null
+++ b/src/test/resources/pyyaml/no-alias-anchor.emitter-error
@@ -0,0 +1,8 @@
+- !StreamStart
+- !DocumentStart
+- !SequenceStart
+- !Scalar { anchor: A, value: data }
+- !Alias { }
+- !SequenceEnd
+- !DocumentEnd
+- !StreamEnd
diff --git a/src/test/resources/pyyaml/no-block-collection-end.loader-error b/src/test/resources/pyyaml/no-block-collection-end.loader-error
new file mode 100644
index 00000000..02d4d377
--- /dev/null
+++ b/src/test/resources/pyyaml/no-block-collection-end.loader-error
@@ -0,0 +1,3 @@
+- foo
+- bar
+baz: bar
diff --git a/src/test/resources/pyyaml/no-block-mapping-end-2.loader-error b/src/test/resources/pyyaml/no-block-mapping-end-2.loader-error
new file mode 100644
index 00000000..be63571f
--- /dev/null
+++ b/src/test/resources/pyyaml/no-block-mapping-end-2.loader-error
@@ -0,0 +1,3 @@
+? foo
+: bar
+: baz
diff --git a/src/test/resources/pyyaml/no-block-mapping-end.loader-error b/src/test/resources/pyyaml/no-block-mapping-end.loader-error
new file mode 100644
index 00000000..1ea921cf
--- /dev/null
+++ b/src/test/resources/pyyaml/no-block-mapping-end.loader-error
@@ -0,0 +1 @@
+foo: "bar" "baz"
diff --git a/src/test/resources/pyyaml/no-document-start.loader-error b/src/test/resources/pyyaml/no-document-start.loader-error
new file mode 100644
index 00000000..c725ec8b
--- /dev/null
+++ b/src/test/resources/pyyaml/no-document-start.loader-error
@@ -0,0 +1,3 @@
+%YAML 1.1
+# no ---
+foo: bar
diff --git a/src/test/resources/pyyaml/no-flow-mapping-end.loader-error b/src/test/resources/pyyaml/no-flow-mapping-end.loader-error
new file mode 100644
index 00000000..8bd1403f
--- /dev/null
+++ b/src/test/resources/pyyaml/no-flow-mapping-end.loader-error
@@ -0,0 +1 @@
+{ foo: bar ]
diff --git a/src/test/resources/pyyaml/no-flow-sequence-end.loader-error b/src/test/resources/pyyaml/no-flow-sequence-end.loader-error
new file mode 100644
index 00000000..750d973b
--- /dev/null
+++ b/src/test/resources/pyyaml/no-flow-sequence-end.loader-error
@@ -0,0 +1 @@
+[foo, bar}
diff --git a/src/test/resources/pyyaml/no-node-1.loader-error b/src/test/resources/pyyaml/no-node-1.loader-error
new file mode 100644
index 00000000..07b15009
--- /dev/null
+++ b/src/test/resources/pyyaml/no-node-1.loader-error
@@ -0,0 +1 @@
+- !foo ]
diff --git a/src/test/resources/pyyaml/no-node-2.loader-error b/src/test/resources/pyyaml/no-node-2.loader-error
new file mode 100644
index 00000000..563e3b34
--- /dev/null
+++ b/src/test/resources/pyyaml/no-node-2.loader-error
@@ -0,0 +1 @@
+- [ !foo } ]
diff --git a/src/test/resources/pyyaml/no-tag.emitter-error b/src/test/resources/pyyaml/no-tag.emitter-error
new file mode 100644
index 00000000..384c62f0
--- /dev/null
+++ b/src/test/resources/pyyaml/no-tag.emitter-error
@@ -0,0 +1,5 @@
+- !StreamStart
+- !DocumentStart
+- !Scalar { value: 'foo', implicit: [false,false] }
+- !DocumentEnd
+- !StreamEnd
diff --git a/src/test/resources/pyyaml/null.data b/src/test/resources/pyyaml/null.data
new file mode 100644
index 00000000..ad125286
--- /dev/null
+++ b/src/test/resources/pyyaml/null.data
@@ -0,0 +1,3 @@
+-
+- ~
+- null
diff --git a/src/test/resources/pyyaml/odd-utf16.stream-error b/src/test/resources/pyyaml/odd-utf16.stream-error
new file mode 100644
index 00000000..37da060a
--- /dev/null
+++ b/src/test/resources/pyyaml/odd-utf16.stream-error
Binary files differ
diff --git a/src/test/resources/pyyaml/remove-possible-simple-key-bug.loader-error b/src/test/resources/pyyaml/remove-possible-simple-key-bug.loader-error
new file mode 100644
index 00000000..fe1bc6c5
--- /dev/null
+++ b/src/test/resources/pyyaml/remove-possible-simple-key-bug.loader-error
@@ -0,0 +1,3 @@
+foo: &A bar
+*A ] # The ']' indicator triggers remove_possible_simple_key,
+ # which should raise an error.
diff --git a/src/test/resources/pyyaml/resolver.data b/src/test/resources/pyyaml/resolver.data
new file mode 100644
index 00000000..a2964048
--- /dev/null
+++ b/src/test/resources/pyyaml/resolver.data
@@ -0,0 +1,30 @@
+---
+"this scalar should be selected"
+---
+key11: !foo
+ key12:
+ is: [selected]
+ key22:
+ key13: [not, selected]
+ key23: [not, selected]
+ key32:
+ key31: [not, selected]
+ key32: [not, selected]
+ key33: {not: selected}
+key21: !bar
+ - not selected
+ - selected
+ - not selected
+key31: !baz
+ key12:
+ key13:
+ key14: {selected}
+ key23:
+ key14: [not, selected]
+ key33:
+ key14: {selected}
+ key24: {not: selected}
+ key22:
+ - key14: {selected}
+ key24: {not: selected}
+ - key14: {selected}
diff --git a/src/test/resources/pyyaml/run-parser-crash-bug.data b/src/test/resources/pyyaml/run-parser-crash-bug.data
new file mode 100644
index 00000000..fe017342
--- /dev/null
+++ b/src/test/resources/pyyaml/run-parser-crash-bug.data
@@ -0,0 +1,8 @@
+---
+- Harry Potter and the Prisoner of Azkaban
+- Harry Potter and the Goblet of Fire
+- Harry Potter and the Order of the Phoenix
+---
+- Memoirs Found in a Bathtub
+- Snow Crash
+- Ghost World
diff --git a/src/test/resources/pyyaml/scalars.events b/src/test/resources/pyyaml/scalars.events
new file mode 100644
index 00000000..32c40f46
--- /dev/null
+++ b/src/test/resources/pyyaml/scalars.events
@@ -0,0 +1,28 @@
+- !StreamStart
+
+- !DocumentStart
+- !MappingStart
+- !Scalar { implicit: [true,true], value: 'empty scalar' }
+- !Scalar { implicit: [true,false], value: '' }
+- !Scalar { implicit: [true,true], value: 'implicit scalar' }
+- !Scalar { implicit: [true,true], value: 'data' }
+- !Scalar { implicit: [true,true], value: 'quoted scalar' }
+- !Scalar { value: 'data', style: '"' }
+- !Scalar { implicit: [true,true], value: 'block scalar' }
+- !Scalar { value: 'data', style: '|' }
+- !Scalar { implicit: [true,true], value: 'empty scalar with tag' }
+- !Scalar { implicit: [false,false], tag: '!mytag', value: '' }
+- !Scalar { implicit: [true,true], value: 'implicit scalar with tag' }
+- !Scalar { implicit: [false,false], tag: '!mytag', value: 'data' }
+- !Scalar { implicit: [true,true], value: 'quoted scalar with tag' }
+- !Scalar { value: 'data', style: '"', tag: '!mytag', implicit: [false,false] }
+- !Scalar { implicit: [true,true], value: 'block scalar with tag' }
+- !Scalar { value: 'data', style: '|', tag: '!mytag', implicit: [false,false] }
+- !Scalar { implicit: [true,true], value: 'single character' }
+- !Scalar { value: 'a', implicit: [true,true] }
+- !Scalar { implicit: [true,true], value: 'single digit' }
+- !Scalar { value: '1', implicit: [true,false] }
+- !MappingEnd
+- !DocumentEnd
+
+- !StreamEnd
diff --git a/src/test/resources/pyyaml/scan-document-end-bug.canonical b/src/test/resources/pyyaml/scan-document-end-bug.canonical
new file mode 100644
index 00000000..4a0e8a82
--- /dev/null
+++ b/src/test/resources/pyyaml/scan-document-end-bug.canonical
@@ -0,0 +1,3 @@
+%YAML 1.1
+---
+!!null ""
diff --git a/src/test/resources/pyyaml/scan-document-end-bug.data b/src/test/resources/pyyaml/scan-document-end-bug.data
new file mode 100644
index 00000000..3c70543b
--- /dev/null
+++ b/src/test/resources/pyyaml/scan-document-end-bug.data
@@ -0,0 +1,3 @@
+# Ticket #4
+---
+... \ No newline at end of file
diff --git a/src/test/resources/pyyaml/scan-line-break-bug.canonical b/src/test/resources/pyyaml/scan-line-break-bug.canonical
new file mode 100644
index 00000000..79f08b74
--- /dev/null
+++ b/src/test/resources/pyyaml/scan-line-break-bug.canonical
@@ -0,0 +1,3 @@
+%YAML 1.1
+---
+!!map { ? !!str "foo" : !!str "bar baz" }
diff --git a/src/test/resources/pyyaml/scan-line-break-bug.data b/src/test/resources/pyyaml/scan-line-break-bug.data
new file mode 100644
index 00000000..c974fab0
--- /dev/null
+++ b/src/test/resources/pyyaml/scan-line-break-bug.data
@@ -0,0 +1,3 @@
+foo:
+ bar
+ baz
diff --git a/src/test/resources/pyyaml/sequences.events b/src/test/resources/pyyaml/sequences.events
new file mode 100644
index 00000000..692a3290
--- /dev/null
+++ b/src/test/resources/pyyaml/sequences.events
@@ -0,0 +1,81 @@
+- !StreamStart
+
+- !DocumentStart
+- !SequenceStart
+- !SequenceEnd
+- !DocumentEnd
+
+- !DocumentStart
+- !SequenceStart { tag: '!mytag', implicit: false }
+- !SequenceEnd
+- !DocumentEnd
+
+- !DocumentStart
+- !SequenceStart
+- !SequenceStart
+- !SequenceEnd
+- !SequenceStart { tag: '!mytag', implicit: false }
+- !SequenceEnd
+- !SequenceStart
+- !Scalar
+- !Scalar { value: 'data' }
+- !Scalar { tag: '!mytag', implicit: [false,false], value: 'data' }
+- !SequenceEnd
+- !SequenceStart
+- !SequenceStart
+- !SequenceStart
+- !Scalar
+- !SequenceEnd
+- !SequenceEnd
+- !SequenceEnd
+- !SequenceStart
+- !SequenceStart { tag: '!mytag', implicit: false }
+- !SequenceStart
+- !Scalar { value: 'data' }
+- !SequenceEnd
+- !SequenceEnd
+- !SequenceEnd
+- !SequenceEnd
+- !DocumentEnd
+
+- !DocumentStart
+- !SequenceStart
+- !MappingStart
+- !Scalar { value: 'key1' }
+- !SequenceStart
+- !Scalar { value: 'data1' }
+- !Scalar { value: 'data2' }
+- !SequenceEnd
+- !Scalar { value: 'key2' }
+- !SequenceStart { tag: '!mytag1', implicit: false }
+- !Scalar { value: 'data3' }
+- !SequenceStart
+- !Scalar { value: 'data4' }
+- !Scalar { value: 'data5' }
+- !SequenceEnd
+- !SequenceStart { tag: '!mytag2', implicit: false }
+- !Scalar { value: 'data6' }
+- !Scalar { value: 'data7' }
+- !SequenceEnd
+- !SequenceEnd
+- !MappingEnd
+- !SequenceEnd
+- !DocumentEnd
+
+- !DocumentStart
+- !SequenceStart
+- !SequenceStart { flow_style: true }
+- !SequenceStart
+- !SequenceEnd
+- !Scalar
+- !Scalar { value: 'data' }
+- !Scalar { tag: '!mytag', implicit: [false,false], value: 'data' }
+- !SequenceStart { tag: '!mytag', implicit: false }
+- !Scalar { value: 'data' }
+- !Scalar { value: 'data' }
+- !SequenceEnd
+- !SequenceEnd
+- !SequenceEnd
+- !DocumentEnd
+
+- !StreamEnd
diff --git a/src/test/resources/pyyaml/single-dot-is-not-float-bug.data b/src/test/resources/pyyaml/single-dot-is-not-float-bug.data
new file mode 100644
index 00000000..9c558e35
--- /dev/null
+++ b/src/test/resources/pyyaml/single-dot-is-not-float-bug.data
@@ -0,0 +1 @@
+.
diff --git a/src/test/resources/pyyaml/sloppy-indentation.canonical b/src/test/resources/pyyaml/sloppy-indentation.canonical
new file mode 100644
index 00000000..438bc04a
--- /dev/null
+++ b/src/test/resources/pyyaml/sloppy-indentation.canonical
@@ -0,0 +1,18 @@
+%YAML 1.1
+---
+!!map {
+ ? !!str "in the block context"
+ : !!map {
+ ? !!str "indentation should be kept"
+ : !!map {
+ ? !!str "but in the flow context"
+ : !!seq [ !!str "it may be violated" ]
+ }
+ }
+}
+--- !!str
+"the parser does not require scalars to be indented with at least one space"
+--- !!str
+"the parser does not require scalars to be indented with at least one space"
+--- !!map
+{ ? !!str "foo": { ? !!str "bar" : !!str "quoted scalars may not adhere indentation" } }
diff --git a/src/test/resources/pyyaml/sloppy-indentation.data b/src/test/resources/pyyaml/sloppy-indentation.data
new file mode 100644
index 00000000..2eb4f5a5
--- /dev/null
+++ b/src/test/resources/pyyaml/sloppy-indentation.data
@@ -0,0 +1,17 @@
+---
+in the block context:
+ indentation should be kept: {
+ but in the flow context: [
+it may be violated]
+}
+---
+the parser does not require scalars
+to be indented with at least one space
+...
+---
+"the parser does not require scalars
+to be indented with at least one space"
+---
+foo:
+ bar: 'quoted scalars
+may not adhere indentation'
diff --git a/src/test/resources/pyyaml/spec-02-01.data b/src/test/resources/pyyaml/spec-02-01.data
new file mode 100644
index 00000000..d12e6711
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-01.data
@@ -0,0 +1,3 @@
+- Mark McGwire
+- Sammy Sosa
+- Ken Griffey
diff --git a/src/test/resources/pyyaml/spec-02-01.tokens b/src/test/resources/pyyaml/spec-02-01.tokens
new file mode 100644
index 00000000..ce44caca
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-01.tokens
@@ -0,0 +1 @@
+[[ , _ , _ , _ ]}
diff --git a/src/test/resources/pyyaml/spec-02-02.data b/src/test/resources/pyyaml/spec-02-02.data
new file mode 100644
index 00000000..7b7ec948
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-02.data
@@ -0,0 +1,3 @@
+hr: 65 # Home runs
+avg: 0.278 # Batting average
+rbi: 147 # Runs Batted In
diff --git a/src/test/resources/pyyaml/spec-02-02.tokens b/src/test/resources/pyyaml/spec-02-02.tokens
new file mode 100644
index 00000000..e4e381b4
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-02.tokens
@@ -0,0 +1,5 @@
+{{
+? _ : _
+? _ : _
+? _ : _
+]}
diff --git a/src/test/resources/pyyaml/spec-02-03.data b/src/test/resources/pyyaml/spec-02-03.data
new file mode 100644
index 00000000..656d628e
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-03.data
@@ -0,0 +1,8 @@
+american:
+ - Boston Red Sox
+ - Detroit Tigers
+ - New York Yankees
+national:
+ - New York Mets
+ - Chicago Cubs
+ - Atlanta Braves
diff --git a/src/test/resources/pyyaml/spec-02-03.tokens b/src/test/resources/pyyaml/spec-02-03.tokens
new file mode 100644
index 00000000..89815f29
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-03.tokens
@@ -0,0 +1,4 @@
+{{
+? _ : [[ , _ , _ , _ ]}
+? _ : [[ , _ , _ , _ ]}
+]}
diff --git a/src/test/resources/pyyaml/spec-02-04.data b/src/test/resources/pyyaml/spec-02-04.data
new file mode 100644
index 00000000..430f6b3d
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-04.data
@@ -0,0 +1,8 @@
+-
+ name: Mark McGwire
+ hr: 65
+ avg: 0.278
+-
+ name: Sammy Sosa
+ hr: 63
+ avg: 0.288
diff --git a/src/test/resources/pyyaml/spec-02-04.tokens b/src/test/resources/pyyaml/spec-02-04.tokens
new file mode 100644
index 00000000..9cb98156
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-04.tokens
@@ -0,0 +1,4 @@
+[[
+, {{ ? _ : _ ? _ : _ ? _ : _ ]}
+, {{ ? _ : _ ? _ : _ ? _ : _ ]}
+]}
diff --git a/src/test/resources/pyyaml/spec-02-05.data b/src/test/resources/pyyaml/spec-02-05.data
new file mode 100644
index 00000000..cdd77706
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-05.data
@@ -0,0 +1,3 @@
+- [name , hr, avg ]
+- [Mark McGwire, 65, 0.278]
+- [Sammy Sosa , 63, 0.288]
diff --git a/src/test/resources/pyyaml/spec-02-05.tokens b/src/test/resources/pyyaml/spec-02-05.tokens
new file mode 100644
index 00000000..3f6f1ab5
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-05.tokens
@@ -0,0 +1,5 @@
+[[
+, [ _ , _ , _ ]
+, [ _ , _ , _ ]
+, [ _ , _ , _ ]
+]}
diff --git a/src/test/resources/pyyaml/spec-02-06.data b/src/test/resources/pyyaml/spec-02-06.data
new file mode 100644
index 00000000..7a957b23
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-06.data
@@ -0,0 +1,5 @@
+Mark McGwire: {hr: 65, avg: 0.278}
+Sammy Sosa: {
+ hr: 63,
+ avg: 0.288
+ }
diff --git a/src/test/resources/pyyaml/spec-02-06.tokens b/src/test/resources/pyyaml/spec-02-06.tokens
new file mode 100644
index 00000000..a1a5eef2
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-06.tokens
@@ -0,0 +1,4 @@
+{{
+? _ : { ? _ : _ , ? _ : _ }
+? _ : { ? _ : _ , ? _ : _ }
+]}
diff --git a/src/test/resources/pyyaml/spec-02-07.data b/src/test/resources/pyyaml/spec-02-07.data
new file mode 100644
index 00000000..bc711d54
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-07.data
@@ -0,0 +1,10 @@
+# Ranking of 1998 home runs
+---
+- Mark McGwire
+- Sammy Sosa
+- Ken Griffey
+
+# Team ranking
+---
+- Chicago Cubs
+- St Louis Cardinals
diff --git a/src/test/resources/pyyaml/spec-02-07.tokens b/src/test/resources/pyyaml/spec-02-07.tokens
new file mode 100644
index 00000000..ed48883c
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-07.tokens
@@ -0,0 +1,12 @@
+---
+[[
+, _
+, _
+, _
+]}
+
+---
+[[
+, _
+, _
+]}
diff --git a/src/test/resources/pyyaml/spec-02-08.data b/src/test/resources/pyyaml/spec-02-08.data
new file mode 100644
index 00000000..05e102d8
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-08.data
@@ -0,0 +1,10 @@
+---
+time: 20:03:20
+player: Sammy Sosa
+action: strike (miss)
+...
+---
+time: 20:03:47
+player: Sammy Sosa
+action: grand slam
+...
diff --git a/src/test/resources/pyyaml/spec-02-08.tokens b/src/test/resources/pyyaml/spec-02-08.tokens
new file mode 100644
index 00000000..7d2c03df
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-08.tokens
@@ -0,0 +1,15 @@
+---
+{{
+? _ : _
+? _ : _
+? _ : _
+]}
+...
+
+---
+{{
+? _ : _
+? _ : _
+? _ : _
+]}
+...
diff --git a/src/test/resources/pyyaml/spec-02-09.data b/src/test/resources/pyyaml/spec-02-09.data
new file mode 100644
index 00000000..e2641805
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-09.data
@@ -0,0 +1,8 @@
+---
+hr: # 1998 hr ranking
+ - Mark McGwire
+ - Sammy Sosa
+rbi:
+ # 1998 rbi ranking
+ - Sammy Sosa
+ - Ken Griffey
diff --git a/src/test/resources/pyyaml/spec-02-09.tokens b/src/test/resources/pyyaml/spec-02-09.tokens
new file mode 100644
index 00000000..b2ec10ea
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-09.tokens
@@ -0,0 +1,5 @@
+---
+{{
+? _ : [[ , _ , _ ]}
+? _ : [[ , _ , _ ]}
+]}
diff --git a/src/test/resources/pyyaml/spec-02-10.data b/src/test/resources/pyyaml/spec-02-10.data
new file mode 100644
index 00000000..61808f67
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-10.data
@@ -0,0 +1,8 @@
+---
+hr:
+ - Mark McGwire
+ # Following node labeled SS
+ - &SS Sammy Sosa
+rbi:
+ - *SS # Subsequent occurrence
+ - Ken Griffey
diff --git a/src/test/resources/pyyaml/spec-02-10.tokens b/src/test/resources/pyyaml/spec-02-10.tokens
new file mode 100644
index 00000000..26caa2b1
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-10.tokens
@@ -0,0 +1,5 @@
+---
+{{
+? _ : [[ , _ , & _ ]}
+? _ : [[ , * , _ ]}
+]}
diff --git a/src/test/resources/pyyaml/spec-02-11.data b/src/test/resources/pyyaml/spec-02-11.data
new file mode 100644
index 00000000..9123ce21
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-11.data
@@ -0,0 +1,9 @@
+? - Detroit Tigers
+ - Chicago cubs
+:
+ - 2001-07-23
+
+? [ New York Yankees,
+ Atlanta Braves ]
+: [ 2001-07-02, 2001-08-12,
+ 2001-08-14 ]
diff --git a/src/test/resources/pyyaml/spec-02-11.tokens b/src/test/resources/pyyaml/spec-02-11.tokens
new file mode 100644
index 00000000..fe242033
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-11.tokens
@@ -0,0 +1,6 @@
+{{
+? [[ , _ , _ ]}
+: [[ , _ ]}
+? [ _ , _ ]
+: [ _ , _ , _ ]
+]}
diff --git a/src/test/resources/pyyaml/spec-02-12.data b/src/test/resources/pyyaml/spec-02-12.data
new file mode 100644
index 00000000..1fc33f9d
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-12.data
@@ -0,0 +1,8 @@
+---
+# products purchased
+- item : Super Hoop
+ quantity: 1
+- item : Basketball
+ quantity: 4
+- item : Big Shoes
+ quantity: 1
diff --git a/src/test/resources/pyyaml/spec-02-12.tokens b/src/test/resources/pyyaml/spec-02-12.tokens
new file mode 100644
index 00000000..ea21e506
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-12.tokens
@@ -0,0 +1,6 @@
+---
+[[
+, {{ ? _ : _ ? _ : _ ]}
+, {{ ? _ : _ ? _ : _ ]}
+, {{ ? _ : _ ? _ : _ ]}
+]}
diff --git a/src/test/resources/pyyaml/spec-02-13.data b/src/test/resources/pyyaml/spec-02-13.data
new file mode 100644
index 00000000..13fb6560
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-13.data
@@ -0,0 +1,4 @@
+# ASCII Art
+--- |
+ \//||\/||
+ // || ||__
diff --git a/src/test/resources/pyyaml/spec-02-13.tokens b/src/test/resources/pyyaml/spec-02-13.tokens
new file mode 100644
index 00000000..7456c055
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-13.tokens
@@ -0,0 +1 @@
+--- _
diff --git a/src/test/resources/pyyaml/spec-02-14.data b/src/test/resources/pyyaml/spec-02-14.data
new file mode 100644
index 00000000..59943def
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-14.data
@@ -0,0 +1,4 @@
+---
+ Mark McGwire's
+ year was crippled
+ by a knee injury.
diff --git a/src/test/resources/pyyaml/spec-02-14.tokens b/src/test/resources/pyyaml/spec-02-14.tokens
new file mode 100644
index 00000000..7456c055
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-14.tokens
@@ -0,0 +1 @@
+--- _
diff --git a/src/test/resources/pyyaml/spec-02-15.data b/src/test/resources/pyyaml/spec-02-15.data
new file mode 100644
index 00000000..80b89a6d
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-15.data
@@ -0,0 +1,8 @@
+>
+ Sammy Sosa completed another
+ fine season with great stats.
+
+ 63 Home Runs
+ 0.288 Batting Average
+
+ What a year!
diff --git a/src/test/resources/pyyaml/spec-02-15.tokens b/src/test/resources/pyyaml/spec-02-15.tokens
new file mode 100644
index 00000000..31354ec1
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-15.tokens
@@ -0,0 +1 @@
+_
diff --git a/src/test/resources/pyyaml/spec-02-16.data b/src/test/resources/pyyaml/spec-02-16.data
new file mode 100644
index 00000000..9f66d881
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-16.data
@@ -0,0 +1,7 @@
+name: Mark McGwire
+accomplishment: >
+ Mark set a major league
+ home run record in 1998.
+stats: |
+ 65 Home Runs
+ 0.278 Batting Average
diff --git a/src/test/resources/pyyaml/spec-02-16.tokens b/src/test/resources/pyyaml/spec-02-16.tokens
new file mode 100644
index 00000000..e4e381b4
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-16.tokens
@@ -0,0 +1,5 @@
+{{
+? _ : _
+? _ : _
+? _ : _
+]}
diff --git a/src/test/resources/pyyaml/spec-02-17.data b/src/test/resources/pyyaml/spec-02-17.data
new file mode 100644
index 00000000..3e899c08
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-17.data
@@ -0,0 +1,7 @@
+unicode: "Sosa did fine.\u263A"
+control: "\b1998\t1999\t2000\n"
+hexesc: "\x0D\x0A is \r\n"
+
+single: '"Howdy!" he cried.'
+quoted: ' # not a ''comment''.'
+tie-fighter: '|\-*-/|'
diff --git a/src/test/resources/pyyaml/spec-02-17.tokens b/src/test/resources/pyyaml/spec-02-17.tokens
new file mode 100644
index 00000000..db655402
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-17.tokens
@@ -0,0 +1,8 @@
+{{
+? _ : _
+? _ : _
+? _ : _
+? _ : _
+? _ : _
+? _ : _
+]}
diff --git a/src/test/resources/pyyaml/spec-02-18.data b/src/test/resources/pyyaml/spec-02-18.data
new file mode 100644
index 00000000..e0a8bfa9
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-18.data
@@ -0,0 +1,6 @@
+plain:
+ This unquoted scalar
+ spans many lines.
+
+quoted: "So does this
+ quoted scalar.\n"
diff --git a/src/test/resources/pyyaml/spec-02-18.tokens b/src/test/resources/pyyaml/spec-02-18.tokens
new file mode 100644
index 00000000..83b31dc0
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-18.tokens
@@ -0,0 +1,4 @@
+{{
+? _ : _
+? _ : _
+]}
diff --git a/src/test/resources/pyyaml/spec-02-19.data b/src/test/resources/pyyaml/spec-02-19.data
new file mode 100644
index 00000000..bf69de69
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-19.data
@@ -0,0 +1,5 @@
+canonical: 12345
+decimal: +12,345
+sexagesimal: 3:25:45
+octal: 014
+hexadecimal: 0xC
diff --git a/src/test/resources/pyyaml/spec-02-19.tokens b/src/test/resources/pyyaml/spec-02-19.tokens
new file mode 100644
index 00000000..5bda68f4
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-19.tokens
@@ -0,0 +1,7 @@
+{{
+? _ : _
+? _ : _
+? _ : _
+? _ : _
+? _ : _
+]}
diff --git a/src/test/resources/pyyaml/spec-02-20.data b/src/test/resources/pyyaml/spec-02-20.data
new file mode 100644
index 00000000..1d4897ff
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-20.data
@@ -0,0 +1,6 @@
+canonical: 1.23015e+3
+exponential: 12.3015e+02
+sexagesimal: 20:30.15
+fixed: 1,230.15
+negative infinity: -.inf
+not a number: .NaN
diff --git a/src/test/resources/pyyaml/spec-02-20.tokens b/src/test/resources/pyyaml/spec-02-20.tokens
new file mode 100644
index 00000000..db655402
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-20.tokens
@@ -0,0 +1,8 @@
+{{
+? _ : _
+? _ : _
+? _ : _
+? _ : _
+? _ : _
+? _ : _
+]}
diff --git a/src/test/resources/pyyaml/spec-02-21.data b/src/test/resources/pyyaml/spec-02-21.data
new file mode 100644
index 00000000..dec6a56b
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-21.data
@@ -0,0 +1,4 @@
+null: ~
+true: y
+false: n
+string: '12345'
diff --git a/src/test/resources/pyyaml/spec-02-21.tokens b/src/test/resources/pyyaml/spec-02-21.tokens
new file mode 100644
index 00000000..aeccbaf6
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-21.tokens
@@ -0,0 +1,6 @@
+{{
+? _ : _
+? _ : _
+? _ : _
+? _ : _
+]}
diff --git a/src/test/resources/pyyaml/spec-02-22.data b/src/test/resources/pyyaml/spec-02-22.data
new file mode 100644
index 00000000..aaac185a
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-22.data
@@ -0,0 +1,4 @@
+canonical: 2001-12-15T02:59:43.1Z
+iso8601: 2001-12-14t21:59:43.10-05:00
+spaced: 2001-12-14 21:59:43.10 -5
+date: 2002-12-14
diff --git a/src/test/resources/pyyaml/spec-02-22.tokens b/src/test/resources/pyyaml/spec-02-22.tokens
new file mode 100644
index 00000000..aeccbaf6
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-22.tokens
@@ -0,0 +1,6 @@
+{{
+? _ : _
+? _ : _
+? _ : _
+? _ : _
+]}
diff --git a/src/test/resources/pyyaml/spec-02-23.data b/src/test/resources/pyyaml/spec-02-23.data
new file mode 100644
index 00000000..5dbd992d
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-23.data
@@ -0,0 +1,13 @@
+---
+not-date: !!str 2002-04-28
+
+picture: !!binary |
+ R0lGODlhDAAMAIQAAP//9/X
+ 17unp5WZmZgAAAOfn515eXv
+ Pz7Y6OjuDg4J+fn5OTk6enp
+ 56enmleECcgggoBADs=
+
+application specific tag: !something |
+ The semantics of the tag
+ above may be different for
+ different documents.
diff --git a/src/test/resources/pyyaml/spec-02-23.tokens b/src/test/resources/pyyaml/spec-02-23.tokens
new file mode 100644
index 00000000..9ac54aad
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-23.tokens
@@ -0,0 +1,6 @@
+---
+{{
+? _ : ! _
+? _ : ! _
+? _ : ! _
+]}
diff --git a/src/test/resources/pyyaml/spec-02-24.data b/src/test/resources/pyyaml/spec-02-24.data
new file mode 100644
index 00000000..1180757d
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-24.data
@@ -0,0 +1,14 @@
+%TAG ! tag:clarkevans.com,2002:
+--- !shape
+ # Use the ! handle for presenting
+ # tag:clarkevans.com,2002:circle
+- !circle
+ center: &ORIGIN {x: 73, y: 129}
+ radius: 7
+- !line
+ start: *ORIGIN
+ finish: { x: 89, y: 102 }
+- !label
+ start: *ORIGIN
+ color: 0xFFEEBB
+ text: Pretty vector drawing.
diff --git a/src/test/resources/pyyaml/spec-02-24.tokens b/src/test/resources/pyyaml/spec-02-24.tokens
new file mode 100644
index 00000000..039c3857
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-24.tokens
@@ -0,0 +1,20 @@
+%
+--- !
+[[
+, !
+ {{
+ ? _ : & { ? _ : _ , ? _ : _ }
+ ? _ : _
+ ]}
+, !
+ {{
+ ? _ : *
+ ? _ : { ? _ : _ , ? _ : _ }
+ ]}
+, !
+ {{
+ ? _ : *
+ ? _ : _
+ ? _ : _
+ ]}
+]}
diff --git a/src/test/resources/pyyaml/spec-02-25.data b/src/test/resources/pyyaml/spec-02-25.data
new file mode 100644
index 00000000..769ac319
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-25.data
@@ -0,0 +1,7 @@
+# sets are represented as a
+# mapping where each key is
+# associated with the empty string
+--- !!set
+? Mark McGwire
+? Sammy Sosa
+? Ken Griff
diff --git a/src/test/resources/pyyaml/spec-02-25.tokens b/src/test/resources/pyyaml/spec-02-25.tokens
new file mode 100644
index 00000000..b7002368
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-25.tokens
@@ -0,0 +1,6 @@
+--- !
+{{
+? _
+? _
+? _
+]}
diff --git a/src/test/resources/pyyaml/spec-02-26.data b/src/test/resources/pyyaml/spec-02-26.data
new file mode 100644
index 00000000..3143763d
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-26.data
@@ -0,0 +1,7 @@
+# ordered maps are represented as
+# a sequence of mappings, with
+# each mapping having one key
+--- !!omap
+- Mark McGwire: 65
+- Sammy Sosa: 63
+- Ken Griffy: 58
diff --git a/src/test/resources/pyyaml/spec-02-26.tokens b/src/test/resources/pyyaml/spec-02-26.tokens
new file mode 100644
index 00000000..7bee4920
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-26.tokens
@@ -0,0 +1,6 @@
+--- !
+[[
+, {{ ? _ : _ ]}
+, {{ ? _ : _ ]}
+, {{ ? _ : _ ]}
+]}
diff --git a/src/test/resources/pyyaml/spec-02-27.data b/src/test/resources/pyyaml/spec-02-27.data
new file mode 100644
index 00000000..4625739d
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-27.data
@@ -0,0 +1,29 @@
+--- !<tag:clarkevans.com,2002:invoice>
+invoice: 34843
+date : 2001-01-23
+bill-to: &id001
+ given : Chris
+ family : Dumars
+ address:
+ lines: |
+ 458 Walkman Dr.
+ Suite #292
+ city : Royal Oak
+ state : MI
+ postal : 48046
+ship-to: *id001
+product:
+ - sku : BL394D
+ quantity : 4
+ description : Basketball
+ price : 450.00
+ - sku : BL4438H
+ quantity : 1
+ description : Super Hoop
+ price : 2392.00
+tax : 251.42
+total: 4443.52
+comments:
+ Late afternoon is best.
+ Backup contact is Nancy
+ Billsmer @ 338-4338.
diff --git a/src/test/resources/pyyaml/spec-02-27.tokens b/src/test/resources/pyyaml/spec-02-27.tokens
new file mode 100644
index 00000000..2dc1c25d
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-27.tokens
@@ -0,0 +1,20 @@
+--- !
+{{
+? _ : _
+? _ : _
+? _ : &
+ {{
+ ? _ : _
+ ? _ : _
+ ? _ : {{ ? _ : _ ? _ : _ ? _ : _ ? _ : _ ]}
+ ]}
+? _ : *
+? _ :
+ [[
+ , {{ ? _ : _ ? _ : _ ? _ : _ ? _ : _ ]}
+ , {{ ? _ : _ ? _ : _ ? _ : _ ? _ : _ ]}
+ ]}
+? _ : _
+? _ : _
+? _ : _
+]}
diff --git a/src/test/resources/pyyaml/spec-02-28.data b/src/test/resources/pyyaml/spec-02-28.data
new file mode 100644
index 00000000..a5c8dc85
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-28.data
@@ -0,0 +1,26 @@
+---
+Time: 2001-11-23 15:01:42 -5
+User: ed
+Warning:
+ This is an error message
+ for the log file
+---
+Time: 2001-11-23 15:02:31 -5
+User: ed
+Warning:
+ A slightly different error
+ message.
+---
+Date: 2001-11-23 15:03:17 -5
+User: ed
+Fatal:
+ Unknown variable "bar"
+Stack:
+ - file: TopClass.py
+ line: 23
+ code: |
+ x = MoreObject("345\n")
+ - file: MoreClass.py
+ line: 58
+ code: |-
+ foo = bar
diff --git a/src/test/resources/pyyaml/spec-02-28.tokens b/src/test/resources/pyyaml/spec-02-28.tokens
new file mode 100644
index 00000000..8d5e1bc5
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-02-28.tokens
@@ -0,0 +1,23 @@
+---
+{{
+? _ : _
+? _ : _
+? _ : _
+]}
+---
+{{
+? _ : _
+? _ : _
+? _ : _
+]}
+---
+{{
+? _ : _
+? _ : _
+? _ : _
+? _ :
+ [[
+ , {{ ? _ : _ ? _ : _ ? _ : _ ]}
+ , {{ ? _ : _ ? _ : _ ? _ : _ ]}
+ ]}
+]}
diff --git a/src/test/resources/pyyaml/spec-05-01-utf16be.data b/src/test/resources/pyyaml/spec-05-01-utf16be.data
new file mode 100644
index 00000000..35250629
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-05-01-utf16be.data
Binary files differ
diff --git a/src/test/resources/pyyaml/spec-05-01-utf16le.data b/src/test/resources/pyyaml/spec-05-01-utf16le.data
new file mode 100644
index 00000000..0823f749
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-05-01-utf16le.data
Binary files differ
diff --git a/src/test/resources/pyyaml/spec-05-01-utf8.data b/src/test/resources/pyyaml/spec-05-01-utf8.data
new file mode 100644
index 00000000..780d25bf
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-05-01-utf8.data
@@ -0,0 +1 @@
+# Comment only.
diff --git a/src/test/resources/pyyaml/spec-05-02-utf16be.data b/src/test/resources/pyyaml/spec-05-02-utf16be.data
new file mode 100644
index 00000000..5ebbb04e
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-05-02-utf16be.data
Binary files differ
diff --git a/src/test/resources/pyyaml/spec-05-02-utf16le.data b/src/test/resources/pyyaml/spec-05-02-utf16le.data
new file mode 100644
index 00000000..0cd90a2b
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-05-02-utf16le.data
Binary files differ
diff --git a/src/test/resources/pyyaml/spec-05-02-utf8.data b/src/test/resources/pyyaml/spec-05-02-utf8.data
new file mode 100644
index 00000000..fb74866f
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-05-02-utf8.data
@@ -0,0 +1,3 @@
+# Invalid use of BOM
+# inside a
+# document.
diff --git a/src/test/resources/pyyaml/spec-05-03.canonical b/src/test/resources/pyyaml/spec-05-03.canonical
new file mode 100644
index 00000000..a143a73f
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-05-03.canonical
@@ -0,0 +1,14 @@
+%YAML 1.1
+---
+!!map {
+ ? !!str "sequence"
+ : !!seq [
+ !!str "one", !!str "two"
+ ],
+ ? !!str "mapping"
+ : !!map {
+ ? !!str "sky" : !!str "blue",
+# ? !!str "sea" : !!str "green",
+ ? !!map { ? !!str "sea" : !!str "green" } : !!null "",
+ }
+}
diff --git a/src/test/resources/pyyaml/spec-05-03.data b/src/test/resources/pyyaml/spec-05-03.data
new file mode 100644
index 00000000..4661f333
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-05-03.data
@@ -0,0 +1,7 @@
+sequence:
+- one
+- two
+mapping:
+ ? sky
+ : blue
+ ? sea : green
diff --git a/src/test/resources/pyyaml/spec-05-04.canonical b/src/test/resources/pyyaml/spec-05-04.canonical
new file mode 100644
index 00000000..00c97236
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-05-04.canonical
@@ -0,0 +1,13 @@
+%YAML 1.1
+---
+!!map {
+ ? !!str "sequence"
+ : !!seq [
+ !!str "one", !!str "two"
+ ],
+ ? !!str "mapping"
+ : !!map {
+ ? !!str "sky" : !!str "blue",
+ ? !!str "sea" : !!str "green",
+ }
+}
diff --git a/src/test/resources/pyyaml/spec-05-04.data b/src/test/resources/pyyaml/spec-05-04.data
new file mode 100644
index 00000000..df338477
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-05-04.data
@@ -0,0 +1,2 @@
+sequence: [ one, two, ]
+mapping: { sky: blue, sea: green }
diff --git a/src/test/resources/pyyaml/spec-05-05.data b/src/test/resources/pyyaml/spec-05-05.data
new file mode 100644
index 00000000..62524c0d
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-05-05.data
@@ -0,0 +1 @@
+# Comment only.
diff --git a/src/test/resources/pyyaml/spec-05-06.canonical b/src/test/resources/pyyaml/spec-05-06.canonical
new file mode 100644
index 00000000..4f30c111
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-05-06.canonical
@@ -0,0 +1,8 @@
+%YAML 1.1
+---
+!!map {
+ ? !!str "anchored"
+ : &A1 !local "value",
+ ? !!str "alias"
+ : *A1,
+}
diff --git a/src/test/resources/pyyaml/spec-05-06.data b/src/test/resources/pyyaml/spec-05-06.data
new file mode 100644
index 00000000..7a1f9b30
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-05-06.data
@@ -0,0 +1,2 @@
+anchored: !local &anchor value
+alias: *anchor
diff --git a/src/test/resources/pyyaml/spec-05-07.canonical b/src/test/resources/pyyaml/spec-05-07.canonical
new file mode 100644
index 00000000..dc3732a5
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-05-07.canonical
@@ -0,0 +1,8 @@
+%YAML 1.1
+---
+!!map {
+ ? !!str "literal"
+ : !!str "text\n",
+ ? !!str "folded"
+ : !!str "text\n",
+}
diff --git a/src/test/resources/pyyaml/spec-05-07.data b/src/test/resources/pyyaml/spec-05-07.data
new file mode 100644
index 00000000..97eb3a34
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-05-07.data
@@ -0,0 +1,4 @@
+literal: |
+ text
+folded: >
+ text
diff --git a/src/test/resources/pyyaml/spec-05-08.canonical b/src/test/resources/pyyaml/spec-05-08.canonical
new file mode 100644
index 00000000..610bd687
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-05-08.canonical
@@ -0,0 +1,8 @@
+%YAML 1.1
+---
+!!map {
+ ? !!str "single"
+ : !!str "text",
+ ? !!str "double"
+ : !!str "text",
+}
diff --git a/src/test/resources/pyyaml/spec-05-08.data b/src/test/resources/pyyaml/spec-05-08.data
new file mode 100644
index 00000000..04ebf691
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-05-08.data
@@ -0,0 +1,2 @@
+single: 'text'
+double: "text"
diff --git a/src/test/resources/pyyaml/spec-05-09.canonical b/src/test/resources/pyyaml/spec-05-09.canonical
new file mode 100644
index 00000000..597e3dea
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-05-09.canonical
@@ -0,0 +1,3 @@
+%YAML 1.1
+---
+!!str "text"
diff --git a/src/test/resources/pyyaml/spec-05-09.data b/src/test/resources/pyyaml/spec-05-09.data
new file mode 100644
index 00000000..a43431bd
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-05-09.data
@@ -0,0 +1,2 @@
+%YAML 1.1
+--- text
diff --git a/src/test/resources/pyyaml/spec-05-10.data b/src/test/resources/pyyaml/spec-05-10.data
new file mode 100644
index 00000000..a4caf911
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-05-10.data
@@ -0,0 +1,2 @@
+commercial-at: @text
+grave-accent: `text
diff --git a/src/test/resources/pyyaml/spec-05-11.canonical b/src/test/resources/pyyaml/spec-05-11.canonical
new file mode 100644
index 00000000..fc25bef4
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-05-11.canonical
@@ -0,0 +1,6 @@
+%YAML 1.1
+--- !!str
+"Generic line break (no glyph)\n\
+ Generic line break (glyphed)\n\
+ Line separator\u2028\
+ Paragraph separator\u2029"
diff --git a/src/test/resources/pyyaml/spec-05-11.data b/src/test/resources/pyyaml/spec-05-11.data
new file mode 100644
index 00000000..b448b759
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-05-11.data
@@ -0,0 +1,3 @@
+|
+ Generic line break (no glyph)
+ Generic line break (glyphed)… Line separator
 Paragraph separator
 \ No newline at end of file
diff --git a/src/test/resources/pyyaml/spec-05-12.data b/src/test/resources/pyyaml/spec-05-12.data
new file mode 100644
index 00000000..7c3ad7f3
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-05-12.data
@@ -0,0 +1,9 @@
+# Tabs do's and don'ts:
+# comment:
+quoted: "Quoted "
+block: |
+ void main() {
+ printf("Hello, world!\n");
+ }
+elsewhere: # separation
+ indentation, in plain scalar
diff --git a/src/test/resources/pyyaml/spec-05-13.canonical b/src/test/resources/pyyaml/spec-05-13.canonical
new file mode 100644
index 00000000..90c1c5c3
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-05-13.canonical
@@ -0,0 +1,5 @@
+%YAML 1.1
+--- !!str
+"Text containing \
+ both space and \
+ tab characters"
diff --git a/src/test/resources/pyyaml/spec-05-13.data b/src/test/resources/pyyaml/spec-05-13.data
new file mode 100644
index 00000000..fce7951c
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-05-13.data
@@ -0,0 +1,3 @@
+ "Text containing
+ both space and
+ tab characters"
diff --git a/src/test/resources/pyyaml/spec-05-14.canonical b/src/test/resources/pyyaml/spec-05-14.canonical
new file mode 100644
index 00000000..4bff01cb
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-05-14.canonical
@@ -0,0 +1,7 @@
+%YAML 1.1
+---
+"Fun with \x5C
+ \x22 \x07 \x08 \x1B \x0C
+ \x0A \x0D \x09 \x0B \x00
+ \x20 \xA0 \x85 \u2028 \u2029
+ A A A"
diff --git a/src/test/resources/pyyaml/spec-05-14.data b/src/test/resources/pyyaml/spec-05-14.data
new file mode 100644
index 00000000..d6e8ce49
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-05-14.data
@@ -0,0 +1,2 @@
+"Fun with \\
+ \" \a \b \e \f \… \n \r \t \v \0 \
 \ \_ \N \L \P \
 \x41 \u0041 \U00000041"
diff --git a/src/test/resources/pyyaml/spec-05-15.data b/src/test/resources/pyyaml/spec-05-15.data
new file mode 100644
index 00000000..7bf12b6c
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-05-15.data
@@ -0,0 +1,3 @@
+Bad escapes:
+ "\c
+ \xq-"
diff --git a/src/test/resources/pyyaml/spec-06-01.canonical b/src/test/resources/pyyaml/spec-06-01.canonical
new file mode 100644
index 00000000..f17ec922
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-06-01.canonical
@@ -0,0 +1,15 @@
+%YAML 1.1
+---
+!!map {
+ ? !!str "Not indented"
+ : !!map {
+ ? !!str "By one space"
+ : !!str "By four\n spaces\n",
+ ? !!str "Flow style"
+ : !!seq [
+ !!str "By two",
+ !!str "Also by two",
+ !!str "Still by two",
+ ]
+ }
+}
diff --git a/src/test/resources/pyyaml/spec-06-01.data b/src/test/resources/pyyaml/spec-06-01.data
new file mode 100644
index 00000000..6134ba12
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-06-01.data
@@ -0,0 +1,14 @@
+ # Leading comment line spaces are
+ # neither content nor indentation.
+
+Not indented:
+ By one space: |
+ By four
+ spaces
+ Flow style: [ # Leading spaces
+ By two, # in flow style
+ Also by two, # are neither
+# Tabs are not allowed:
+# Still by two # content nor
+ Still by two # content nor
+ ] # indentation.
diff --git a/src/test/resources/pyyaml/spec-06-02.data b/src/test/resources/pyyaml/spec-06-02.data
new file mode 100644
index 00000000..ff741e5f
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-06-02.data
@@ -0,0 +1,3 @@
+ # Comment
+
+
diff --git a/src/test/resources/pyyaml/spec-06-03.canonical b/src/test/resources/pyyaml/spec-06-03.canonical
new file mode 100644
index 00000000..ec269022
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-06-03.canonical
@@ -0,0 +1,6 @@
+%YAML 1.1
+---
+!!map {
+ ? !!str "key"
+ : !!str "value"
+}
diff --git a/src/test/resources/pyyaml/spec-06-03.data b/src/test/resources/pyyaml/spec-06-03.data
new file mode 100644
index 00000000..9db09129
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-06-03.data
@@ -0,0 +1,2 @@
+key: # Comment
+ value
diff --git a/src/test/resources/pyyaml/spec-06-04.canonical b/src/test/resources/pyyaml/spec-06-04.canonical
new file mode 100644
index 00000000..ec269022
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-06-04.canonical
@@ -0,0 +1,6 @@
+%YAML 1.1
+---
+!!map {
+ ? !!str "key"
+ : !!str "value"
+}
diff --git a/src/test/resources/pyyaml/spec-06-04.data b/src/test/resources/pyyaml/spec-06-04.data
new file mode 100644
index 00000000..86308dd3
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-06-04.data
@@ -0,0 +1,4 @@
+key: # Comment
+ # lines
+ value
+
diff --git a/src/test/resources/pyyaml/spec-06-05.canonical b/src/test/resources/pyyaml/spec-06-05.canonical
new file mode 100644
index 00000000..8da431d0
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-06-05.canonical
@@ -0,0 +1,16 @@
+%YAML 1.1
+---
+!!map {
+ ? !!map {
+ ? !!str "first"
+ : !!str "Sammy",
+ ? !!str "last"
+ : !!str "Sosa"
+ }
+ : !!map {
+ ? !!str "hr"
+ : !!int "65",
+ ? !!str "avg"
+ : !!float "0.278"
+ }
+}
diff --git a/src/test/resources/pyyaml/spec-06-05.data b/src/test/resources/pyyaml/spec-06-05.data
new file mode 100644
index 00000000..37613f5b
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-06-05.data
@@ -0,0 +1,6 @@
+{ first: Sammy, last: Sosa }:
+# Statistics:
+ hr: # Home runs
+ 65
+ avg: # Average
+ 0.278
diff --git a/src/test/resources/pyyaml/spec-06-06.canonical b/src/test/resources/pyyaml/spec-06-06.canonical
new file mode 100644
index 00000000..513d07a1
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-06-06.canonical
@@ -0,0 +1,10 @@
+%YAML 1.1
+---
+!!map {
+ ? !!str "plain"
+ : !!str "text lines",
+ ? !!str "quoted"
+ : !!str "text lines",
+ ? !!str "block"
+ : !!str "text\n lines\n"
+}
diff --git a/src/test/resources/pyyaml/spec-06-06.data b/src/test/resources/pyyaml/spec-06-06.data
new file mode 100644
index 00000000..2f62d082
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-06-06.data
@@ -0,0 +1,7 @@
+plain: text
+ lines
+quoted: "text
+ lines"
+block: |
+ text
+ lines
diff --git a/src/test/resources/pyyaml/spec-06-07.canonical b/src/test/resources/pyyaml/spec-06-07.canonical
new file mode 100644
index 00000000..11357e45
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-06-07.canonical
@@ -0,0 +1,6 @@
+%YAML 1.1
+---
+!!seq [
+ !!str "foo\nbar",
+ !!str "foo\n\nbar"
+]
diff --git a/src/test/resources/pyyaml/spec-06-07.data b/src/test/resources/pyyaml/spec-06-07.data
new file mode 100644
index 00000000..130cfa74
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-06-07.data
@@ -0,0 +1,8 @@
+- foo
+
+ bar
+- |-
+ foo
+
+ bar
+
diff --git a/src/test/resources/pyyaml/spec-06-08.canonical b/src/test/resources/pyyaml/spec-06-08.canonical
new file mode 100644
index 00000000..cc72bc84
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-06-08.canonical
@@ -0,0 +1,5 @@
+%YAML 1.1
+--- !!str
+"specific\L\
+ trimmed\n\n\n\
+ as space"
diff --git a/src/test/resources/pyyaml/spec-06-08.data b/src/test/resources/pyyaml/spec-06-08.data
new file mode 100644
index 00000000..f2896edb
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-06-08.data
@@ -0,0 +1,2 @@
+>-
+ specific
 trimmed… … …… as… space
diff --git a/src/test/resources/pyyaml/spec-07-01.canonical b/src/test/resources/pyyaml/spec-07-01.canonical
new file mode 100644
index 00000000..8c8c48db
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-07-01.canonical
@@ -0,0 +1,3 @@
+%YAML 1.1
+--- !!str
+"foo"
diff --git a/src/test/resources/pyyaml/spec-07-01.data b/src/test/resources/pyyaml/spec-07-01.data
new file mode 100644
index 00000000..2113eb61
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-07-01.data
@@ -0,0 +1,3 @@
+%FOO bar baz # Should be ignored
+ # with a warning.
+--- "foo"
diff --git a/src/test/resources/pyyaml/spec-07-02.canonical b/src/test/resources/pyyaml/spec-07-02.canonical
new file mode 100644
index 00000000..cb7dd1c3
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-07-02.canonical
@@ -0,0 +1,3 @@
+%YAML 1.1
+---
+!!str "foo"
diff --git a/src/test/resources/pyyaml/spec-07-02.data b/src/test/resources/pyyaml/spec-07-02.data
new file mode 100644
index 00000000..c8b73229
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-07-02.data
@@ -0,0 +1,4 @@
+%YAML 1.2 # Attempt parsing
+ # with a warning
+---
+"foo"
diff --git a/src/test/resources/pyyaml/spec-07-03.data b/src/test/resources/pyyaml/spec-07-03.data
new file mode 100644
index 00000000..4bfa07ac
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-07-03.data
@@ -0,0 +1,3 @@
+%YAML 1.1
+%YAML 1.1
+foo
diff --git a/src/test/resources/pyyaml/spec-07-04.canonical b/src/test/resources/pyyaml/spec-07-04.canonical
new file mode 100644
index 00000000..cb7dd1c3
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-07-04.canonical
@@ -0,0 +1,3 @@
+%YAML 1.1
+---
+!!str "foo"
diff --git a/src/test/resources/pyyaml/spec-07-04.data b/src/test/resources/pyyaml/spec-07-04.data
new file mode 100644
index 00000000..50f5ab93
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-07-04.data
@@ -0,0 +1,3 @@
+%TAG !yaml! tag:yaml.org,2002:
+---
+!yaml!str "foo"
diff --git a/src/test/resources/pyyaml/spec-07-05.data b/src/test/resources/pyyaml/spec-07-05.data
new file mode 100644
index 00000000..7276eae9
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-07-05.data
@@ -0,0 +1,3 @@
+%TAG ! !foo
+%TAG ! !foo
+bar
diff --git a/src/test/resources/pyyaml/spec-07-06.canonical b/src/test/resources/pyyaml/spec-07-06.canonical
new file mode 100644
index 00000000..bddf6168
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-07-06.canonical
@@ -0,0 +1,6 @@
+%YAML 1.1
+---
+!!seq [
+ !<!foobar> "baz",
+ !<tag:yaml.org,2002:str> "string"
+]
diff --git a/src/test/resources/pyyaml/spec-07-06.data b/src/test/resources/pyyaml/spec-07-06.data
new file mode 100644
index 00000000..d9854cbd
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-07-06.data
@@ -0,0 +1,5 @@
+%TAG ! !foo
+%TAG !yaml! tag:yaml.org,2002:
+---
+- !bar "baz"
+- !yaml!str "string"
diff --git a/src/test/resources/pyyaml/spec-07-07a.canonical b/src/test/resources/pyyaml/spec-07-07a.canonical
new file mode 100644
index 00000000..fa086df9
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-07-07a.canonical
@@ -0,0 +1,3 @@
+%YAML 1.1
+---
+!<!foo> "bar"
diff --git a/src/test/resources/pyyaml/spec-07-07a.data b/src/test/resources/pyyaml/spec-07-07a.data
new file mode 100644
index 00000000..9d42ec3d
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-07-07a.data
@@ -0,0 +1,2 @@
+# Private application:
+!foo "bar"
diff --git a/src/test/resources/pyyaml/spec-07-07b.canonical b/src/test/resources/pyyaml/spec-07-07b.canonical
new file mode 100644
index 00000000..fe917d84
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-07-07b.canonical
@@ -0,0 +1,3 @@
+%YAML 1.1
+---
+!<tag:ben-kiki.org,2000:app/foo> "bar"
diff --git a/src/test/resources/pyyaml/spec-07-07b.data b/src/test/resources/pyyaml/spec-07-07b.data
new file mode 100644
index 00000000..2d36d0e0
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-07-07b.data
@@ -0,0 +1,4 @@
+# Migrated to global:
+%TAG ! tag:ben-kiki.org,2000:app/
+---
+!foo "bar"
diff --git a/src/test/resources/pyyaml/spec-07-08.canonical b/src/test/resources/pyyaml/spec-07-08.canonical
new file mode 100644
index 00000000..703aa7b4
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-07-08.canonical
@@ -0,0 +1,7 @@
+%YAML 1.1
+---
+!!seq [
+ !<!foo> "bar",
+ !<tag:yaml.org,2002:str> "string",
+ !<tag:ben-kiki.org,2000:type> "baz"
+]
diff --git a/src/test/resources/pyyaml/spec-07-08.data b/src/test/resources/pyyaml/spec-07-08.data
new file mode 100644
index 00000000..e2c6d9e1
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-07-08.data
@@ -0,0 +1,9 @@
+# Explicitly specify default settings:
+%TAG ! !
+%TAG !! tag:yaml.org,2002:
+# Named handles have no default:
+%TAG !o! tag:ben-kiki.org,2000:
+---
+- !foo "bar"
+- !!str "string"
+- !o!type "baz"
diff --git a/src/test/resources/pyyaml/spec-07-09.canonical b/src/test/resources/pyyaml/spec-07-09.canonical
new file mode 100644
index 00000000..32d9e943
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-07-09.canonical
@@ -0,0 +1,9 @@
+%YAML 1.1
+---
+!!str "foo"
+%YAML 1.1
+---
+!!str "bar"
+%YAML 1.1
+---
+!!str "baz"
diff --git a/src/test/resources/pyyaml/spec-07-09.data b/src/test/resources/pyyaml/spec-07-09.data
new file mode 100644
index 00000000..1209d47b
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-07-09.data
@@ -0,0 +1,11 @@
+---
+foo
+...
+# Repeated end marker.
+...
+---
+bar
+# No end marker.
+---
+baz
+...
diff --git a/src/test/resources/pyyaml/spec-07-10.canonical b/src/test/resources/pyyaml/spec-07-10.canonical
new file mode 100644
index 00000000..1db650a8
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-07-10.canonical
@@ -0,0 +1,15 @@
+%YAML 1.1
+---
+!!str "Root flow scalar"
+%YAML 1.1
+---
+!!str "Root block scalar\n"
+%YAML 1.1
+---
+!!map {
+ ? !!str "foo"
+ : !!str "bar"
+}
+---
+#!!str ""
+!!null ""
diff --git a/src/test/resources/pyyaml/spec-07-10.data b/src/test/resources/pyyaml/spec-07-10.data
new file mode 100644
index 00000000..6939b392
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-07-10.data
@@ -0,0 +1,11 @@
+"Root flow
+ scalar"
+--- !!str >
+ Root block
+ scalar
+---
+# Root collection:
+foo : bar
+... # Is optional.
+---
+# Explicit document may be empty.
diff --git a/src/test/resources/pyyaml/spec-07-11.data b/src/test/resources/pyyaml/spec-07-11.data
new file mode 100644
index 00000000..d11302da
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-07-11.data
@@ -0,0 +1,2 @@
+# A stream may contain
+# no documents.
diff --git a/src/test/resources/pyyaml/spec-07-12a.canonical b/src/test/resources/pyyaml/spec-07-12a.canonical
new file mode 100644
index 00000000..efc116f1
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-07-12a.canonical
@@ -0,0 +1,6 @@
+%YAML 1.1
+---
+!!map {
+ ? !!str "foo"
+ : !!str "bar"
+}
diff --git a/src/test/resources/pyyaml/spec-07-12a.data b/src/test/resources/pyyaml/spec-07-12a.data
new file mode 100644
index 00000000..3807d57d
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-07-12a.data
@@ -0,0 +1,3 @@
+# Implicit document. Root
+# collection (mapping) node.
+foo : bar
diff --git a/src/test/resources/pyyaml/spec-07-12b.canonical b/src/test/resources/pyyaml/spec-07-12b.canonical
new file mode 100644
index 00000000..04bcffc8
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-07-12b.canonical
@@ -0,0 +1,3 @@
+%YAML 1.1
+---
+!!str "Text content\n"
diff --git a/src/test/resources/pyyaml/spec-07-12b.data b/src/test/resources/pyyaml/spec-07-12b.data
new file mode 100644
index 00000000..43250db3
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-07-12b.data
@@ -0,0 +1,4 @@
+# Explicit document. Root
+# scalar (literal) node.
+--- |
+ Text content
diff --git a/src/test/resources/pyyaml/spec-07-13.canonical b/src/test/resources/pyyaml/spec-07-13.canonical
new file mode 100644
index 00000000..5af71e91
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-07-13.canonical
@@ -0,0 +1,9 @@
+%YAML 1.1
+---
+!!str "First document"
+---
+!<!foo> "No directives"
+---
+!<!foobar> "With directives"
+---
+!<!baz> "Reset settings"
diff --git a/src/test/resources/pyyaml/spec-07-13.data b/src/test/resources/pyyaml/spec-07-13.data
new file mode 100644
index 00000000..ba7ec63e
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-07-13.data
@@ -0,0 +1,9 @@
+! "First document"
+---
+!foo "No directives"
+%TAG ! !foo
+---
+!bar "With directives"
+%YAML 1.1
+---
+!baz "Reset settings"
diff --git a/src/test/resources/pyyaml/spec-08-01.canonical b/src/test/resources/pyyaml/spec-08-01.canonical
new file mode 100644
index 00000000..69e4161b
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-08-01.canonical
@@ -0,0 +1,8 @@
+%YAML 1.1
+---
+!!map {
+ ? &A1 !!str "foo"
+ : !!str "bar",
+ ? &A2 !!str "baz"
+ : *A1
+}
diff --git a/src/test/resources/pyyaml/spec-08-01.data b/src/test/resources/pyyaml/spec-08-01.data
new file mode 100644
index 00000000..48986ecb
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-08-01.data
@@ -0,0 +1,2 @@
+!!str &a1 "foo" : !!str bar
+&a2 baz : *a1
diff --git a/src/test/resources/pyyaml/spec-08-02.canonical b/src/test/resources/pyyaml/spec-08-02.canonical
new file mode 100644
index 00000000..dd6f76ec
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-08-02.canonical
@@ -0,0 +1,8 @@
+%YAML 1.1
+---
+!!map {
+ ? !!str "First occurrence"
+ : &A !!str "Value",
+ ? !!str "Second occurrence"
+ : *A
+}
diff --git a/src/test/resources/pyyaml/spec-08-02.data b/src/test/resources/pyyaml/spec-08-02.data
new file mode 100644
index 00000000..600d1792
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-08-02.data
@@ -0,0 +1,2 @@
+First occurrence: &anchor Value
+Second occurrence: *anchor
diff --git a/src/test/resources/pyyaml/spec-08-03.canonical b/src/test/resources/pyyaml/spec-08-03.canonical
new file mode 100644
index 00000000..be7ea8f3
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-08-03.canonical
@@ -0,0 +1,6 @@
+%YAML 1.1
+---
+!!map {
+ ? !<tag:yaml.org,2002:str> "foo"
+ : !<!bar> "baz"
+}
diff --git a/src/test/resources/pyyaml/spec-08-03.data b/src/test/resources/pyyaml/spec-08-03.data
new file mode 100644
index 00000000..8e51f52a
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-08-03.data
@@ -0,0 +1,2 @@
+!<tag:yaml.org,2002:str> foo :
+ !<!bar> baz
diff --git a/src/test/resources/pyyaml/spec-08-04.data b/src/test/resources/pyyaml/spec-08-04.data
new file mode 100644
index 00000000..f7d1b01e
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-08-04.data
@@ -0,0 +1,2 @@
+- !<!> foo
+- !<$:?> bar
diff --git a/src/test/resources/pyyaml/spec-08-05.canonical b/src/test/resources/pyyaml/spec-08-05.canonical
new file mode 100644
index 00000000..a5c710ae
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-08-05.canonical
@@ -0,0 +1,7 @@
+%YAML 1.1
+---
+!!seq [
+ !<!local> "foo",
+ !<tag:yaml.org,2002:str> "bar",
+ !<tag:ben-kiki.org,2000:type> "baz",
+]
diff --git a/src/test/resources/pyyaml/spec-08-05.data b/src/test/resources/pyyaml/spec-08-05.data
new file mode 100644
index 00000000..93576ed7
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-08-05.data
@@ -0,0 +1,5 @@
+%TAG !o! tag:ben-kiki.org,2000:
+---
+- !local foo
+- !!str bar
+- !o!type baz
diff --git a/src/test/resources/pyyaml/spec-08-06.data b/src/test/resources/pyyaml/spec-08-06.data
new file mode 100644
index 00000000..85800105
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-08-06.data
@@ -0,0 +1,5 @@
+%TAG !o! tag:ben-kiki.org,2000:
+---
+- !$a!b foo
+- !o! bar
+- !h!type baz
diff --git a/src/test/resources/pyyaml/spec-08-07.canonical b/src/test/resources/pyyaml/spec-08-07.canonical
new file mode 100644
index 00000000..e2f43d97
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-08-07.canonical
@@ -0,0 +1,8 @@
+%YAML 1.1
+---
+!!seq [
+ !<tag:yaml.org,2002:str> "12",
+ !<tag:yaml.org,2002:int> "12",
+# !<tag:yaml.org,2002:str> "12",
+ !<tag:yaml.org,2002:int> "12",
+]
diff --git a/src/test/resources/pyyaml/spec-08-07.data b/src/test/resources/pyyaml/spec-08-07.data
new file mode 100644
index 00000000..98aa565e
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-08-07.data
@@ -0,0 +1,4 @@
+# Assuming conventional resolution:
+- "12"
+- 12
+- ! 12
diff --git a/src/test/resources/pyyaml/spec-08-08.canonical b/src/test/resources/pyyaml/spec-08-08.canonical
new file mode 100644
index 00000000..d3f8b1a7
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-08-08.canonical
@@ -0,0 +1,15 @@
+%YAML 1.1
+---
+!!map {
+ ? !!str "foo"
+ : !!str "bar baz"
+}
+%YAML 1.1
+---
+!!str "foo bar"
+%YAML 1.1
+---
+!!str "foo bar"
+%YAML 1.1
+---
+!!str "foo\n"
diff --git a/src/test/resources/pyyaml/spec-08-08.data b/src/test/resources/pyyaml/spec-08-08.data
new file mode 100644
index 00000000..757a93dd
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-08-08.data
@@ -0,0 +1,13 @@
+---
+foo:
+ "bar
+ baz"
+---
+"foo
+ bar"
+---
+foo
+ bar
+--- |
+ foo
+...
diff --git a/src/test/resources/pyyaml/spec-08-09.canonical b/src/test/resources/pyyaml/spec-08-09.canonical
new file mode 100644
index 00000000..3805daf0
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-08-09.canonical
@@ -0,0 +1,21 @@
+%YAML 1.1
+--- !!map {
+ ? !!str "scalars" : !!map {
+ ? !!str "plain"
+ : !!str "some text",
+ ? !!str "quoted"
+ : !!map {
+ ? !!str "single"
+ : !!str "some text",
+ ? !!str "double"
+ : !!str "some text"
+ } },
+ ? !!str "collections" : !!map {
+ ? !!str "sequence" : !!seq [
+ !!str "entry",
+ !!map {
+ ? !!str "key" : !!str "value"
+ } ],
+ ? !!str "mapping" : !!map {
+ ? !!str "key" : !!str "value"
+} } }
diff --git a/src/test/resources/pyyaml/spec-08-09.data b/src/test/resources/pyyaml/spec-08-09.data
new file mode 100644
index 00000000..69da0422
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-08-09.data
@@ -0,0 +1,11 @@
+---
+scalars:
+ plain: !!str some text
+ quoted:
+ single: 'some text'
+ double: "some text"
+collections:
+ sequence: !!seq [ !!str entry,
+ # Mapping entry:
+ key: value ]
+ mapping: { key: value }
diff --git a/src/test/resources/pyyaml/spec-08-10.canonical b/src/test/resources/pyyaml/spec-08-10.canonical
new file mode 100644
index 00000000..8281c5ef
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-08-10.canonical
@@ -0,0 +1,23 @@
+%YAML 1.1
+---
+!!map {
+ ? !!str "block styles" : !!map {
+ ? !!str "scalars" : !!map {
+ ? !!str "literal"
+ : !!str "#!/usr/bin/perl\n\
+ print \"Hello,
+ world!\\n\";\n",
+ ? !!str "folded"
+ : !!str "This sentence
+ is false.\n"
+ },
+ ? !!str "collections" : !!map {
+ ? !!str "sequence" : !!seq [
+ !!str "entry",
+ !!map {
+ ? !!str "key" : !!str "value"
+ }
+ ],
+ ? !!str "mapping" : !!map {
+ ? !!str "key" : !!str "value"
+} } } }
diff --git a/src/test/resources/pyyaml/spec-08-10.data b/src/test/resources/pyyaml/spec-08-10.data
new file mode 100644
index 00000000..72acc56b
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-08-10.data
@@ -0,0 +1,15 @@
+block styles:
+ scalars:
+ literal: !!str |
+ #!/usr/bin/perl
+ print "Hello, world!\n";
+ folded: >
+ This sentence
+ is false.
+ collections: !!map
+ sequence: !!seq # Entry:
+ - entry # Plain
+ # Mapping entry:
+ - key: value
+ mapping:
+ key: value
diff --git a/src/test/resources/pyyaml/spec-08-11.canonical b/src/test/resources/pyyaml/spec-08-11.canonical
new file mode 100644
index 00000000..dd6f76ec
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-08-11.canonical
@@ -0,0 +1,8 @@
+%YAML 1.1
+---
+!!map {
+ ? !!str "First occurrence"
+ : &A !!str "Value",
+ ? !!str "Second occurrence"
+ : *A
+}
diff --git a/src/test/resources/pyyaml/spec-08-11.data b/src/test/resources/pyyaml/spec-08-11.data
new file mode 100644
index 00000000..600d1792
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-08-11.data
@@ -0,0 +1,2 @@
+First occurrence: &anchor Value
+Second occurrence: *anchor
diff --git a/src/test/resources/pyyaml/spec-08-12.canonical b/src/test/resources/pyyaml/spec-08-12.canonical
new file mode 100644
index 00000000..93899f4e
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-08-12.canonical
@@ -0,0 +1,10 @@
+%YAML 1.1
+---
+!!seq [
+ !!str "Without properties",
+ &A !!str "Anchored",
+ !!str "Tagged",
+ *A,
+ !!str "",
+ !!str "",
+]
diff --git a/src/test/resources/pyyaml/spec-08-12.data b/src/test/resources/pyyaml/spec-08-12.data
new file mode 100644
index 00000000..3d4c6b7c
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-08-12.data
@@ -0,0 +1,8 @@
+[
+ Without properties,
+ &anchor "Anchored",
+ !!str 'Tagged',
+ *anchor, # Alias node
+ !!str , # Empty plain scalar
+ '', # Empty plain scalar
+]
diff --git a/src/test/resources/pyyaml/spec-08-13.canonical b/src/test/resources/pyyaml/spec-08-13.canonical
new file mode 100644
index 00000000..618bb7bd
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-08-13.canonical
@@ -0,0 +1,10 @@
+%YAML 1.1
+---
+!!map {
+ ? !!str "foo"
+# : !!str "",
+# ? !!str ""
+ : !!null "",
+ ? !!null ""
+ : !!str "bar",
+}
diff --git a/src/test/resources/pyyaml/spec-08-13.data b/src/test/resources/pyyaml/spec-08-13.data
new file mode 100644
index 00000000..ebe663ac
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-08-13.data
@@ -0,0 +1,4 @@
+{
+ ? foo :,
+ ? : bar,
+}
diff --git a/src/test/resources/pyyaml/spec-08-14.canonical b/src/test/resources/pyyaml/spec-08-14.canonical
new file mode 100644
index 00000000..11db439f
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-08-14.canonical
@@ -0,0 +1,10 @@
+%YAML 1.1
+---
+!!seq [
+ !!str "flow in block",
+ !!str "Block scalar\n",
+ !!map {
+ ? !!str "foo"
+ : !!str "bar"
+ }
+]
diff --git a/src/test/resources/pyyaml/spec-08-14.data b/src/test/resources/pyyaml/spec-08-14.data
new file mode 100644
index 00000000..2fbb1f70
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-08-14.data
@@ -0,0 +1,5 @@
+- "flow in block"
+- >
+ Block scalar
+- !!map # Block collection
+ foo : bar
diff --git a/src/test/resources/pyyaml/spec-08-15.canonical b/src/test/resources/pyyaml/spec-08-15.canonical
new file mode 100644
index 00000000..76f028e6
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-08-15.canonical
@@ -0,0 +1,11 @@
+%YAML 1.1
+---
+!!seq [
+ !!null "",
+ !!map {
+ ? !!str "foo"
+ : !!null "",
+ ? !!null ""
+ : !!str "bar",
+ }
+]
diff --git a/src/test/resources/pyyaml/spec-08-15.data b/src/test/resources/pyyaml/spec-08-15.data
new file mode 100644
index 00000000..7c86bcf3
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-08-15.data
@@ -0,0 +1,5 @@
+- # Empty plain scalar
+- ? foo
+ :
+ ?
+ : bar
diff --git a/src/test/resources/pyyaml/spec-09-01.canonical b/src/test/resources/pyyaml/spec-09-01.canonical
new file mode 100644
index 00000000..e71a5484
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-01.canonical
@@ -0,0 +1,11 @@
+%YAML 1.1
+---
+!!map {
+ ? !!str "simple key"
+ : !!map {
+ ? !!str "also simple"
+ : !!str "value",
+ ? !!str "not a simple key"
+ : !!str "any value"
+ }
+}
diff --git a/src/test/resources/pyyaml/spec-09-01.data b/src/test/resources/pyyaml/spec-09-01.data
new file mode 100644
index 00000000..9e83eaff
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-01.data
@@ -0,0 +1,6 @@
+"simple key" : {
+ "also simple" : value,
+ ? "not a
+ simple key" : "any
+ value"
+}
diff --git a/src/test/resources/pyyaml/spec-09-02.canonical b/src/test/resources/pyyaml/spec-09-02.canonical
new file mode 100644
index 00000000..6f8f41ad
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-02.canonical
@@ -0,0 +1,7 @@
+%YAML 1.1
+---
+!!str "as space \
+ trimmed\n\
+ specific\L\n\
+ escaped\t\n\
+ none"
diff --git a/src/test/resources/pyyaml/spec-09-02.data b/src/test/resources/pyyaml/spec-09-02.data
new file mode 100644
index 00000000..d84883dc
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-02.data
@@ -0,0 +1,6 @@
+ "as space
+ trimmed
+
+ specific

+ escaped \

+ none"
diff --git a/src/test/resources/pyyaml/spec-09-03.canonical b/src/test/resources/pyyaml/spec-09-03.canonical
new file mode 100644
index 00000000..658c6df8
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-03.canonical
@@ -0,0 +1,7 @@
+%YAML 1.1
+---
+!!seq [
+ !!str " last",
+ !!str " last",
+ !!str " \tfirst last",
+]
diff --git a/src/test/resources/pyyaml/spec-09-03.data b/src/test/resources/pyyaml/spec-09-03.data
new file mode 100644
index 00000000..e0b914d7
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-03.data
@@ -0,0 +1,6 @@
+- "
+ last"
+- "
+ last"
+- " first
+ last"
diff --git a/src/test/resources/pyyaml/spec-09-04.canonical b/src/test/resources/pyyaml/spec-09-04.canonical
new file mode 100644
index 00000000..fa466324
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-04.canonical
@@ -0,0 +1,6 @@
+%YAML 1.1
+---
+!!str "first \
+ inner 1 \
+ inner 2 \
+ last"
diff --git a/src/test/resources/pyyaml/spec-09-04.data b/src/test/resources/pyyaml/spec-09-04.data
new file mode 100644
index 00000000..313a91b4
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-04.data
@@ -0,0 +1,4 @@
+ "first
+ inner 1
+ \ inner 2 \
+ last"
diff --git a/src/test/resources/pyyaml/spec-09-05.canonical b/src/test/resources/pyyaml/spec-09-05.canonical
new file mode 100644
index 00000000..24d10528
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-05.canonical
@@ -0,0 +1,7 @@
+%YAML 1.1
+---
+!!seq [
+ !!str "first ",
+ !!str "first\nlast",
+ !!str "first inner \tlast",
+]
diff --git a/src/test/resources/pyyaml/spec-09-05.data b/src/test/resources/pyyaml/spec-09-05.data
new file mode 100644
index 00000000..624c30ea
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-05.data
@@ -0,0 +1,8 @@
+- "first
+ "
+- "first
+
+ last"
+- "first
+ inner
+ \ last"
diff --git a/src/test/resources/pyyaml/spec-09-06.canonical b/src/test/resources/pyyaml/spec-09-06.canonical
new file mode 100644
index 00000000..50287722
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-06.canonical
@@ -0,0 +1,3 @@
+%YAML 1.1
+---
+!!str "here's to \"quotes\""
diff --git a/src/test/resources/pyyaml/spec-09-06.data b/src/test/resources/pyyaml/spec-09-06.data
new file mode 100644
index 00000000..b038078e
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-06.data
@@ -0,0 +1 @@
+ 'here''s to "quotes"'
diff --git a/src/test/resources/pyyaml/spec-09-07.canonical b/src/test/resources/pyyaml/spec-09-07.canonical
new file mode 100644
index 00000000..e71a5484
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-07.canonical
@@ -0,0 +1,11 @@
+%YAML 1.1
+---
+!!map {
+ ? !!str "simple key"
+ : !!map {
+ ? !!str "also simple"
+ : !!str "value",
+ ? !!str "not a simple key"
+ : !!str "any value"
+ }
+}
diff --git a/src/test/resources/pyyaml/spec-09-07.data b/src/test/resources/pyyaml/spec-09-07.data
new file mode 100644
index 00000000..755b54a0
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-07.data
@@ -0,0 +1,6 @@
+'simple key' : {
+ 'also simple' : value,
+ ? 'not a
+ simple key' : 'any
+ value'
+}
diff --git a/src/test/resources/pyyaml/spec-09-08.canonical b/src/test/resources/pyyaml/spec-09-08.canonical
new file mode 100644
index 00000000..06abdb5f
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-08.canonical
@@ -0,0 +1,6 @@
+%YAML 1.1
+---
+!!str "as space \
+ trimmed\n\
+ specific\L\n\
+ none"
diff --git a/src/test/resources/pyyaml/spec-09-08.data b/src/test/resources/pyyaml/spec-09-08.data
new file mode 100644
index 00000000..aa4d4589
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-08.data
@@ -0,0 +1 @@
+ 'as space … trimmed …… specific
… none'
diff --git a/src/test/resources/pyyaml/spec-09-09.canonical b/src/test/resources/pyyaml/spec-09-09.canonical
new file mode 100644
index 00000000..658c6df8
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-09.canonical
@@ -0,0 +1,7 @@
+%YAML 1.1
+---
+!!seq [
+ !!str " last",
+ !!str " last",
+ !!str " \tfirst last",
+]
diff --git a/src/test/resources/pyyaml/spec-09-09.data b/src/test/resources/pyyaml/spec-09-09.data
new file mode 100644
index 00000000..52171df3
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-09.data
@@ -0,0 +1,6 @@
+- '
+ last'
+- '
+ last'
+- ' first
+ last'
diff --git a/src/test/resources/pyyaml/spec-09-10.canonical b/src/test/resources/pyyaml/spec-09-10.canonical
new file mode 100644
index 00000000..2028d044
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-10.canonical
@@ -0,0 +1,5 @@
+%YAML 1.1
+---
+!!str "first \
+ inner \
+ last"
diff --git a/src/test/resources/pyyaml/spec-09-10.data b/src/test/resources/pyyaml/spec-09-10.data
new file mode 100644
index 00000000..0e414495
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-10.data
@@ -0,0 +1,3 @@
+ 'first
+ inner
+ last'
diff --git a/src/test/resources/pyyaml/spec-09-11.canonical b/src/test/resources/pyyaml/spec-09-11.canonical
new file mode 100644
index 00000000..4eb222c9
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-11.canonical
@@ -0,0 +1,6 @@
+%YAML 1.1
+---
+!!seq [
+ !!str "first ",
+ !!str "first\nlast",
+]
diff --git a/src/test/resources/pyyaml/spec-09-11.data b/src/test/resources/pyyaml/spec-09-11.data
new file mode 100644
index 00000000..5efa873b
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-11.data
@@ -0,0 +1,5 @@
+- 'first
+ '
+- 'first
+
+ last'
diff --git a/src/test/resources/pyyaml/spec-09-12.canonical b/src/test/resources/pyyaml/spec-09-12.canonical
new file mode 100644
index 00000000..d8e6dce7
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-12.canonical
@@ -0,0 +1,12 @@
+%YAML 1.1
+---
+!!seq [
+ !!str "::std::vector",
+ !!str "Up, up, and away!",
+ !!int "-123",
+ !!seq [
+ !!str "::std::vector",
+ !!str "Up, up, and away!",
+ !!int "-123",
+ ]
+]
diff --git a/src/test/resources/pyyaml/spec-09-12.data b/src/test/resources/pyyaml/spec-09-12.data
new file mode 100644
index 00000000..b9a3ac53
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-12.data
@@ -0,0 +1,8 @@
+# Outside flow collection:
+- ::std::vector
+- Up, up, and away!
+- -123
+# Inside flow collection:
+- [ '::std::vector',
+ "Up, up, and away!",
+ -123 ]
diff --git a/src/test/resources/pyyaml/spec-09-13.canonical b/src/test/resources/pyyaml/spec-09-13.canonical
new file mode 100644
index 00000000..e71a5484
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-13.canonical
@@ -0,0 +1,11 @@
+%YAML 1.1
+---
+!!map {
+ ? !!str "simple key"
+ : !!map {
+ ? !!str "also simple"
+ : !!str "value",
+ ? !!str "not a simple key"
+ : !!str "any value"
+ }
+}
diff --git a/src/test/resources/pyyaml/spec-09-13.data b/src/test/resources/pyyaml/spec-09-13.data
new file mode 100644
index 00000000..b156386a
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-13.data
@@ -0,0 +1,6 @@
+simple key : {
+ also simple : value,
+ ? not a
+ simple key : any
+ value
+}
diff --git a/src/test/resources/pyyaml/spec-09-14.data b/src/test/resources/pyyaml/spec-09-14.data
new file mode 100644
index 00000000..97f23162
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-14.data
@@ -0,0 +1,14 @@
+---
+--- ||| : foo
+... >>>: bar
+---
+[
+---
+,
+... ,
+{
+--- :
+... # Nested
+}
+]
+...
diff --git a/src/test/resources/pyyaml/spec-09-15.canonical b/src/test/resources/pyyaml/spec-09-15.canonical
new file mode 100644
index 00000000..df020407
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-15.canonical
@@ -0,0 +1,18 @@
+%YAML 1.1
+---
+!!map {
+ ? !!str "---"
+ : !!str "foo",
+ ? !!str "..."
+ : !!str "bar"
+}
+%YAML 1.1
+---
+!!seq [
+ !!str "---",
+ !!str "...",
+ !!map {
+ ? !!str "---"
+ : !!str "..."
+ }
+]
diff --git a/src/test/resources/pyyaml/spec-09-15.data b/src/test/resources/pyyaml/spec-09-15.data
new file mode 100644
index 00000000..e6863b04
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-15.data
@@ -0,0 +1,13 @@
+---
+"---" : foo
+...: bar
+---
+[
+---,
+...,
+{
+? ---
+: ...
+}
+]
+...
diff --git a/src/test/resources/pyyaml/spec-09-16.canonical b/src/test/resources/pyyaml/spec-09-16.canonical
new file mode 100644
index 00000000..06abdb5f
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-16.canonical
@@ -0,0 +1,6 @@
+%YAML 1.1
+---
+!!str "as space \
+ trimmed\n\
+ specific\L\n\
+ none"
diff --git a/src/test/resources/pyyaml/spec-09-16.data b/src/test/resources/pyyaml/spec-09-16.data
new file mode 100644
index 00000000..473beb9a
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-16.data
@@ -0,0 +1,3 @@
+# Tabs are confusing:
+# as space/trimmed/specific/none
+ as space … trimmed …… specific
… none
diff --git a/src/test/resources/pyyaml/spec-09-17.canonical b/src/test/resources/pyyaml/spec-09-17.canonical
new file mode 100644
index 00000000..68cb70d1
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-17.canonical
@@ -0,0 +1,4 @@
+%YAML 1.1
+---
+!!str "first line\n\
+ more line"
diff --git a/src/test/resources/pyyaml/spec-09-17.data b/src/test/resources/pyyaml/spec-09-17.data
new file mode 100644
index 00000000..97bc46c4
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-17.data
@@ -0,0 +1,3 @@
+ first line
+
+ more line
diff --git a/src/test/resources/pyyaml/spec-09-18.canonical b/src/test/resources/pyyaml/spec-09-18.canonical
new file mode 100644
index 00000000..f21428f6
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-18.canonical
@@ -0,0 +1,8 @@
+%YAML 1.1
+---
+!!seq [
+ !!str "literal\n",
+ !!str " folded\n",
+ !!str "keep\n\n",
+ !!str " strip",
+]
diff --git a/src/test/resources/pyyaml/spec-09-18.data b/src/test/resources/pyyaml/spec-09-18.data
new file mode 100644
index 00000000..68c5d7cc
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-18.data
@@ -0,0 +1,9 @@
+- | # Just the style
+ literal
+- >1 # Indentation indicator
+ folded
+- |+ # Chomping indicator
+ keep
+
+- >-1 # Both indicators
+ strip
diff --git a/src/test/resources/pyyaml/spec-09-19.canonical b/src/test/resources/pyyaml/spec-09-19.canonical
new file mode 100644
index 00000000..3e828d7d
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-19.canonical
@@ -0,0 +1,6 @@
+%YAML 1.1
+---
+!!seq [
+ !!str "literal\n",
+ !!str "folded\n",
+]
diff --git a/src/test/resources/pyyaml/spec-09-19.data b/src/test/resources/pyyaml/spec-09-19.data
new file mode 100644
index 00000000..f0e589dc
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-19.data
@@ -0,0 +1,4 @@
+- |
+ literal
+- >
+ folded
diff --git a/src/test/resources/pyyaml/spec-09-20.canonical b/src/test/resources/pyyaml/spec-09-20.canonical
new file mode 100644
index 00000000..d03bef51
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-20.canonical
@@ -0,0 +1,8 @@
+%YAML 1.1
+---
+!!seq [
+ !!str "detected\n",
+ !!str "\n\n# detected\n",
+ !!str " explicit\n",
+ !!str "\t\ndetected\n",
+]
diff --git a/src/test/resources/pyyaml/spec-09-20.data b/src/test/resources/pyyaml/spec-09-20.data
new file mode 100644
index 00000000..39bee044
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-20.data
@@ -0,0 +1,11 @@
+- |
+ detected
+- >
+
+
+ # detected
+- |1
+ explicit
+- >
+
+ detected
diff --git a/src/test/resources/pyyaml/spec-09-21.data b/src/test/resources/pyyaml/spec-09-21.data
new file mode 100644
index 00000000..0fdd14f2
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-21.data
@@ -0,0 +1,8 @@
+- |
+
+ text
+- >
+ text
+ text
+- |1
+ text
diff --git a/src/test/resources/pyyaml/spec-09-22.canonical b/src/test/resources/pyyaml/spec-09-22.canonical
new file mode 100644
index 00000000..c1bbcd22
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-22.canonical
@@ -0,0 +1,10 @@
+%YAML 1.1
+---
+!!map {
+ ? !!str "strip"
+ : !!str "text",
+ ? !!str "clip"
+ : !!str "text\n",
+ ? !!str "keep"
+ : !!str "text\L",
+}
diff --git a/src/test/resources/pyyaml/spec-09-22.data b/src/test/resources/pyyaml/spec-09-22.data
new file mode 100644
index 00000000..0dd51eb3
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-22.data
@@ -0,0 +1,4 @@
+strip: |-
+ text
clip: |
+ text…keep: |+
+ text
 \ No newline at end of file
diff --git a/src/test/resources/pyyaml/spec-09-23.canonical b/src/test/resources/pyyaml/spec-09-23.canonical
new file mode 100644
index 00000000..c4444caa
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-23.canonical
@@ -0,0 +1,10 @@
+%YAML 1.1
+---
+!!map {
+ ? !!str "strip"
+ : !!str "# text",
+ ? !!str "clip"
+ : !!str "# text\n",
+ ? !!str "keep"
+ : !!str "# text\L\n",
+}
diff --git a/src/test/resources/pyyaml/spec-09-23.data b/src/test/resources/pyyaml/spec-09-23.data
new file mode 100644
index 00000000..8972d2b6
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-23.data
@@ -0,0 +1,11 @@
+ # Strip
+ # Comments:
+strip: |-
+ # text
 
 # Clip
+ # comments:
+…clip: |
+ # text… 
 # Keep
+ # comments:
+…keep: |+
+ # text
… # Trail
+ # comments.
diff --git a/src/test/resources/pyyaml/spec-09-24.canonical b/src/test/resources/pyyaml/spec-09-24.canonical
new file mode 100644
index 00000000..45a99b01
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-24.canonical
@@ -0,0 +1,10 @@
+%YAML 1.1
+---
+!!map {
+ ? !!str "strip"
+ : !!str "",
+ ? !!str "clip"
+ : !!str "",
+ ? !!str "keep"
+ : !!str "\n",
+}
diff --git a/src/test/resources/pyyaml/spec-09-24.data b/src/test/resources/pyyaml/spec-09-24.data
new file mode 100644
index 00000000..de0b64bb
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-24.data
@@ -0,0 +1,6 @@
+strip: >-
+
+clip: >
+
+keep: |+
+
diff --git a/src/test/resources/pyyaml/spec-09-25.canonical b/src/test/resources/pyyaml/spec-09-25.canonical
new file mode 100644
index 00000000..9d2327bb
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-25.canonical
@@ -0,0 +1,4 @@
+%YAML 1.1
+---
+!!str "literal\n\
+ \ttext\n"
diff --git a/src/test/resources/pyyaml/spec-09-25.data b/src/test/resources/pyyaml/spec-09-25.data
new file mode 100644
index 00000000..f6303a14
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-25.data
@@ -0,0 +1,3 @@
+| # Simple block scalar
+ literal
+ text
diff --git a/src/test/resources/pyyaml/spec-09-26.canonical b/src/test/resources/pyyaml/spec-09-26.canonical
new file mode 100644
index 00000000..3029a116
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-26.canonical
@@ -0,0 +1,3 @@
+%YAML 1.1
+---
+!!str "\n\nliteral\n\ntext\n"
diff --git a/src/test/resources/pyyaml/spec-09-26.data b/src/test/resources/pyyaml/spec-09-26.data
new file mode 100644
index 00000000..f28555ab
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-26.data
@@ -0,0 +1,8 @@
+|
+
+
+ literal
+
+ text
+
+ # Comment
diff --git a/src/test/resources/pyyaml/spec-09-27.canonical b/src/test/resources/pyyaml/spec-09-27.canonical
new file mode 100644
index 00000000..3029a116
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-27.canonical
@@ -0,0 +1,3 @@
+%YAML 1.1
+---
+!!str "\n\nliteral\n\ntext\n"
diff --git a/src/test/resources/pyyaml/spec-09-27.data b/src/test/resources/pyyaml/spec-09-27.data
new file mode 100644
index 00000000..f28555ab
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-27.data
@@ -0,0 +1,8 @@
+|
+
+
+ literal
+
+ text
+
+ # Comment
diff --git a/src/test/resources/pyyaml/spec-09-28.canonical b/src/test/resources/pyyaml/spec-09-28.canonical
new file mode 100644
index 00000000..3029a116
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-28.canonical
@@ -0,0 +1,3 @@
+%YAML 1.1
+---
+!!str "\n\nliteral\n\ntext\n"
diff --git a/src/test/resources/pyyaml/spec-09-28.data b/src/test/resources/pyyaml/spec-09-28.data
new file mode 100644
index 00000000..f28555ab
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-28.data
@@ -0,0 +1,8 @@
+|
+
+
+ literal
+
+ text
+
+ # Comment
diff --git a/src/test/resources/pyyaml/spec-09-29.canonical b/src/test/resources/pyyaml/spec-09-29.canonical
new file mode 100644
index 00000000..0980789a
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-29.canonical
@@ -0,0 +1,4 @@
+%YAML 1.1
+---
+!!str "folded text\n\
+ \tlines\n"
diff --git a/src/test/resources/pyyaml/spec-09-29.data b/src/test/resources/pyyaml/spec-09-29.data
new file mode 100644
index 00000000..82e611fc
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-29.data
@@ -0,0 +1,4 @@
+> # Simple folded scalar
+ folded
+ text
+ lines
diff --git a/src/test/resources/pyyaml/spec-09-30.canonical b/src/test/resources/pyyaml/spec-09-30.canonical
new file mode 100644
index 00000000..fc37db1c
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-30.canonical
@@ -0,0 +1,7 @@
+%YAML 1.1
+---
+!!str "folded line\n\
+ next line\n\n\
+ \ * bullet\n\
+ \ * list\n\n\
+ last line\n"
diff --git a/src/test/resources/pyyaml/spec-09-30.data b/src/test/resources/pyyaml/spec-09-30.data
new file mode 100644
index 00000000..a4d8c36a
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-30.data
@@ -0,0 +1,14 @@
+>
+ folded
+ line
+
+ next
+ line
+
+ * bullet
+ * list
+
+ last
+ line
+
+# Comment
diff --git a/src/test/resources/pyyaml/spec-09-31.canonical b/src/test/resources/pyyaml/spec-09-31.canonical
new file mode 100644
index 00000000..fc37db1c
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-31.canonical
@@ -0,0 +1,7 @@
+%YAML 1.1
+---
+!!str "folded line\n\
+ next line\n\n\
+ \ * bullet\n\
+ \ * list\n\n\
+ last line\n"
diff --git a/src/test/resources/pyyaml/spec-09-31.data b/src/test/resources/pyyaml/spec-09-31.data
new file mode 100644
index 00000000..a4d8c36a
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-31.data
@@ -0,0 +1,14 @@
+>
+ folded
+ line
+
+ next
+ line
+
+ * bullet
+ * list
+
+ last
+ line
+
+# Comment
diff --git a/src/test/resources/pyyaml/spec-09-32.canonical b/src/test/resources/pyyaml/spec-09-32.canonical
new file mode 100644
index 00000000..fc37db1c
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-32.canonical
@@ -0,0 +1,7 @@
+%YAML 1.1
+---
+!!str "folded line\n\
+ next line\n\n\
+ \ * bullet\n\
+ \ * list\n\n\
+ last line\n"
diff --git a/src/test/resources/pyyaml/spec-09-32.data b/src/test/resources/pyyaml/spec-09-32.data
new file mode 100644
index 00000000..a4d8c36a
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-32.data
@@ -0,0 +1,14 @@
+>
+ folded
+ line
+
+ next
+ line
+
+ * bullet
+ * list
+
+ last
+ line
+
+# Comment
diff --git a/src/test/resources/pyyaml/spec-09-33.canonical b/src/test/resources/pyyaml/spec-09-33.canonical
new file mode 100644
index 00000000..fc37db1c
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-33.canonical
@@ -0,0 +1,7 @@
+%YAML 1.1
+---
+!!str "folded line\n\
+ next line\n\n\
+ \ * bullet\n\
+ \ * list\n\n\
+ last line\n"
diff --git a/src/test/resources/pyyaml/spec-09-33.data b/src/test/resources/pyyaml/spec-09-33.data
new file mode 100644
index 00000000..a4d8c36a
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-09-33.data
@@ -0,0 +1,14 @@
+>
+ folded
+ line
+
+ next
+ line
+
+ * bullet
+ * list
+
+ last
+ line
+
+# Comment
diff --git a/src/test/resources/pyyaml/spec-10-01.canonical b/src/test/resources/pyyaml/spec-10-01.canonical
new file mode 100644
index 00000000..d08cdd40
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-10-01.canonical
@@ -0,0 +1,12 @@
+%YAML 1.1
+---
+!!seq [
+ !!seq [
+ !!str "inner",
+ !!str "inner",
+ ],
+ !!seq [
+ !!str "inner",
+ !!str "last",
+ ],
+]
diff --git a/src/test/resources/pyyaml/spec-10-01.data b/src/test/resources/pyyaml/spec-10-01.data
new file mode 100644
index 00000000..e668d38d
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-10-01.data
@@ -0,0 +1,2 @@
+- [ inner, inner, ]
+- [inner,last]
diff --git a/src/test/resources/pyyaml/spec-10-02.canonical b/src/test/resources/pyyaml/spec-10-02.canonical
new file mode 100644
index 00000000..82fe0d94
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-10-02.canonical
@@ -0,0 +1,14 @@
+%YAML 1.1
+---
+!!seq [
+ !!str "double quoted",
+ !!str "single quoted",
+ !!str "plain text",
+ !!seq [
+ !!str "nested",
+ ],
+ !!map {
+ ? !!str "single"
+ : !!str "pair"
+ }
+]
diff --git a/src/test/resources/pyyaml/spec-10-02.data b/src/test/resources/pyyaml/spec-10-02.data
new file mode 100644
index 00000000..3b233515
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-10-02.data
@@ -0,0 +1,8 @@
+[
+"double
+ quoted", 'single
+ quoted',
+plain
+ text, [ nested ],
+single: pair ,
+]
diff --git a/src/test/resources/pyyaml/spec-10-03.canonical b/src/test/resources/pyyaml/spec-10-03.canonical
new file mode 100644
index 00000000..1443395b
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-10-03.canonical
@@ -0,0 +1,12 @@
+%YAML 1.1
+---
+!!map {
+ ? !!str "block"
+ : !!seq [
+ !!str "one",
+ !!map {
+ ? !!str "two"
+ : !!str "three"
+ }
+ ]
+}
diff --git a/src/test/resources/pyyaml/spec-10-03.data b/src/test/resources/pyyaml/spec-10-03.data
new file mode 100644
index 00000000..9e15f83b
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-10-03.data
@@ -0,0 +1,4 @@
+block: # Block
+ # sequence
+- one
+- two : three
diff --git a/src/test/resources/pyyaml/spec-10-04.canonical b/src/test/resources/pyyaml/spec-10-04.canonical
new file mode 100644
index 00000000..ae486a3c
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-10-04.canonical
@@ -0,0 +1,11 @@
+%YAML 1.1
+---
+!!map {
+ ? !!str "block"
+ : !!seq [
+ !!str "one",
+ !!seq [
+ !!str "two"
+ ]
+ ]
+}
diff --git a/src/test/resources/pyyaml/spec-10-04.data b/src/test/resources/pyyaml/spec-10-04.data
new file mode 100644
index 00000000..2905b0d9
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-10-04.data
@@ -0,0 +1,4 @@
+block:
+- one
+-
+ - two
diff --git a/src/test/resources/pyyaml/spec-10-05.canonical b/src/test/resources/pyyaml/spec-10-05.canonical
new file mode 100644
index 00000000..07cc0c98
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-10-05.canonical
@@ -0,0 +1,14 @@
+%YAML 1.1
+---
+!!seq [
+ !!null "",
+ !!str "block node\n",
+ !!seq [
+ !!str "one",
+ !!str "two",
+ ],
+ !!map {
+ ? !!str "one"
+ : !!str "two",
+ }
+]
diff --git a/src/test/resources/pyyaml/spec-10-05.data b/src/test/resources/pyyaml/spec-10-05.data
new file mode 100644
index 00000000..f19a99e3
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-10-05.data
@@ -0,0 +1,7 @@
+- # Empty
+- |
+ block node
+- - one # in-line
+ - two # sequence
+- one: two # in-line
+ # mapping
diff --git a/src/test/resources/pyyaml/spec-10-06.canonical b/src/test/resources/pyyaml/spec-10-06.canonical
new file mode 100644
index 00000000..d9986c28
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-10-06.canonical
@@ -0,0 +1,16 @@
+%YAML 1.1
+---
+!!seq [
+ !!map {
+ ? !!str "inner"
+ : !!str "entry",
+ ? !!str "also"
+ : !!str "inner"
+ },
+ !!map {
+ ? !!str "inner"
+ : !!str "entry",
+ ? !!str "last"
+ : !!str "entry"
+ }
+]
diff --git a/src/test/resources/pyyaml/spec-10-06.data b/src/test/resources/pyyaml/spec-10-06.data
new file mode 100644
index 00000000..860ba25b
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-10-06.data
@@ -0,0 +1,2 @@
+- { inner : entry , also: inner , }
+- {inner: entry,last : entry}
diff --git a/src/test/resources/pyyaml/spec-10-07.canonical b/src/test/resources/pyyaml/spec-10-07.canonical
new file mode 100644
index 00000000..ec74230a
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-10-07.canonical
@@ -0,0 +1,16 @@
+%YAML 1.1
+---
+!!map {
+ ? !!null ""
+ : !!str "value",
+ ? !!str "explicit key"
+ : !!str "value",
+ ? !!str "simple key"
+ : !!str "value",
+ ? !!seq [
+ !!str "collection",
+ !!str "simple",
+ !!str "key"
+ ]
+ : !!str "value"
+}
diff --git a/src/test/resources/pyyaml/spec-10-07.data b/src/test/resources/pyyaml/spec-10-07.data
new file mode 100644
index 00000000..ff943fbc
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-10-07.data
@@ -0,0 +1,7 @@
+{
+? : value, # Empty key
+? explicit
+ key: value,
+simple key : value,
+[ collection, simple, key ]: value
+}
diff --git a/src/test/resources/pyyaml/spec-10-08.data b/src/test/resources/pyyaml/spec-10-08.data
new file mode 100644
index 00000000..55bd788a
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-10-08.data
@@ -0,0 +1,5 @@
+{
+multi-line
+ simple key : value,
+very long ...................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................(>1KB)................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................... key: value
+}
diff --git a/src/test/resources/pyyaml/spec-10-09.canonical b/src/test/resources/pyyaml/spec-10-09.canonical
new file mode 100644
index 00000000..4d9827b1
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-10-09.canonical
@@ -0,0 +1,8 @@
+%YAML 1.1
+---
+!!map {
+ ? !!str "key"
+ : !!str "value",
+ ? !!str "empty"
+ : !!null "",
+}
diff --git a/src/test/resources/pyyaml/spec-10-09.data b/src/test/resources/pyyaml/spec-10-09.data
new file mode 100644
index 00000000..4d55e21d
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-10-09.data
@@ -0,0 +1,4 @@
+{
+key : value,
+empty: # empty value↓
+}
diff --git a/src/test/resources/pyyaml/spec-10-10.canonical b/src/test/resources/pyyaml/spec-10-10.canonical
new file mode 100644
index 00000000..016fb640
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-10-10.canonical
@@ -0,0 +1,16 @@
+%YAML 1.1
+---
+!!map {
+ ? !!str "explicit key1"
+ : !!str "explicit value",
+ ? !!str "explicit key2"
+ : !!null "",
+ ? !!str "explicit key3"
+ : !!null "",
+ ? !!str "simple key1"
+ : !!str "explicit value",
+ ? !!str "simple key2"
+ : !!null "",
+ ? !!str "simple key3"
+ : !!null "",
+}
diff --git a/src/test/resources/pyyaml/spec-10-10.data b/src/test/resources/pyyaml/spec-10-10.data
new file mode 100644
index 00000000..0888b054
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-10-10.data
@@ -0,0 +1,8 @@
+{
+? explicit key1 : explicit value,
+? explicit key2 : , # Explicit empty
+? explicit key3, # Empty value
+simple key1 : explicit value,
+simple key2 : , # Explicit empty
+simple key3, # Empty value
+}
diff --git a/src/test/resources/pyyaml/spec-10-11.canonical b/src/test/resources/pyyaml/spec-10-11.canonical
new file mode 100644
index 00000000..7309544c
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-10-11.canonical
@@ -0,0 +1,24 @@
+%YAML 1.1
+---
+!!seq [
+ !!map {
+ ? !!str "explicit key1"
+ : !!str "explicit value",
+ },
+ !!map {
+ ? !!str "explicit key2"
+ : !!null "",
+ },
+ !!map {
+ ? !!str "explicit key3"
+ : !!null "",
+ },
+ !!map {
+ ? !!str "simple key1"
+ : !!str "explicit value",
+ },
+ !!map {
+ ? !!str "simple key2"
+ : !!null "",
+ },
+]
diff --git a/src/test/resources/pyyaml/spec-10-11.data b/src/test/resources/pyyaml/spec-10-11.data
new file mode 100644
index 00000000..9f055684
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-10-11.data
@@ -0,0 +1,7 @@
+[
+? explicit key1 : explicit value,
+? explicit key2 : , # Explicit empty
+? explicit key3, # Implicit empty
+simple key1 : explicit value,
+simple key2 : , # Explicit empty
+]
diff --git a/src/test/resources/pyyaml/spec-10-12.canonical b/src/test/resources/pyyaml/spec-10-12.canonical
new file mode 100644
index 00000000..a95dd40c
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-10-12.canonical
@@ -0,0 +1,9 @@
+%YAML 1.1
+---
+!!map {
+ ? !!str "block"
+ : !!map {
+ ? !!str "key"
+ : !!str "value"
+ }
+}
diff --git a/src/test/resources/pyyaml/spec-10-12.data b/src/test/resources/pyyaml/spec-10-12.data
new file mode 100644
index 00000000..55214435
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-10-12.data
@@ -0,0 +1,3 @@
+block: # Block
+ # mapping
+ key: value
diff --git a/src/test/resources/pyyaml/spec-10-13.canonical b/src/test/resources/pyyaml/spec-10-13.canonical
new file mode 100644
index 00000000..e183c50f
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-10-13.canonical
@@ -0,0 +1,11 @@
+%YAML 1.1
+---
+!!map {
+ ? !!str "explicit key"
+ : !!null "",
+ ? !!str "block key\n"
+ : !!seq [
+ !!str "one",
+ !!str "two",
+ ]
+}
diff --git a/src/test/resources/pyyaml/spec-10-13.data b/src/test/resources/pyyaml/spec-10-13.data
new file mode 100644
index 00000000..b5b97db1
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-10-13.data
@@ -0,0 +1,5 @@
+? explicit key # implicit value
+? |
+ block key
+: - one # explicit in-line
+ - two # block value
diff --git a/src/test/resources/pyyaml/spec-10-14.canonical b/src/test/resources/pyyaml/spec-10-14.canonical
new file mode 100644
index 00000000..e87c8805
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-10-14.canonical
@@ -0,0 +1,11 @@
+%YAML 1.1
+---
+!!map {
+ ? !!str "plain key"
+ : !!null "",
+ ? !!str "quoted key"
+ : !!seq [
+ !!str "one",
+ !!str "two",
+ ]
+}
diff --git a/src/test/resources/pyyaml/spec-10-14.data b/src/test/resources/pyyaml/spec-10-14.data
new file mode 100644
index 00000000..7f5995ca
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-10-14.data
@@ -0,0 +1,4 @@
+plain key: # empty value
+"quoted key":
+- one # explicit next-line
+- two # block value
diff --git a/src/test/resources/pyyaml/spec-10-15.canonical b/src/test/resources/pyyaml/spec-10-15.canonical
new file mode 100644
index 00000000..85fbbd06
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-10-15.canonical
@@ -0,0 +1,18 @@
+%YAML 1.1
+---
+!!seq [
+ !!map {
+ ? !!str "sun"
+ : !!str "yellow"
+ },
+ !!map {
+ ? !!map {
+ ? !!str "earth"
+ : !!str "blue"
+ }
+ : !!map {
+ ? !!str "moon"
+ : !!str "white"
+ }
+ }
+]
diff --git a/src/test/resources/pyyaml/spec-10-15.data b/src/test/resources/pyyaml/spec-10-15.data
new file mode 100644
index 00000000..d675cfd6
--- /dev/null
+++ b/src/test/resources/pyyaml/spec-10-15.data
@@ -0,0 +1,3 @@
+- sun: yellow
+- ? earth: blue
+ : moon: white
diff --git a/src/test/resources/pyyaml/str.data b/src/test/resources/pyyaml/str.data
new file mode 100644
index 00000000..7cbdb7c6
--- /dev/null
+++ b/src/test/resources/pyyaml/str.data
@@ -0,0 +1 @@
+- abcd
diff --git a/src/test/resources/pyyaml/tags.events b/src/test/resources/pyyaml/tags.events
new file mode 100644
index 00000000..bb93dce1
--- /dev/null
+++ b/src/test/resources/pyyaml/tags.events
@@ -0,0 +1,12 @@
+- !StreamStart
+- !DocumentStart
+- !SequenceStart
+- !Scalar { value: 'data' }
+#- !Scalar { tag: '!', value: 'data' }
+- !Scalar { tag: 'tag:yaml.org,2002:str', value: 'data' }
+- !Scalar { tag: '!myfunnytag', value: 'data' }
+- !Scalar { tag: '!my!ugly!tag', value: 'data' }
+- !Scalar { tag: 'tag:my.domain.org,2002:data!? #', value: 'data' }
+- !SequenceEnd
+- !DocumentEnd
+- !StreamEnd
diff --git a/src/test/resources/pyyaml/test_mark.marks b/src/test/resources/pyyaml/test_mark.marks
new file mode 100644
index 00000000..cf257b46
--- /dev/null
+++ b/src/test/resources/pyyaml/test_mark.marks
@@ -0,0 +1,38 @@
+---
+*The first line.
+The last line.
+---
+The first*line.
+The last line.
+---
+The first line.*
+The last line.
+---
+The first line.
+*The last line.
+---
+The first line.
+The last*line.
+---
+The first line.
+The last line.*
+---
+The first line.
+*The selected line.
+The last line.
+---
+The first line.
+The selected*line.
+The last line.
+---
+The first line.
+The selected line.*
+The last line.
+---
+*The only line.
+---
+The only*line.
+---
+The only line.*
+---
+Loooooooooooooooooooooooooooooooooooooooooooooong*Liiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiine
diff --git a/src/test/resources/pyyaml/timestamp-bugs.data b/src/test/resources/pyyaml/timestamp-bugs.data
new file mode 100644
index 00000000..721d2908
--- /dev/null
+++ b/src/test/resources/pyyaml/timestamp-bugs.data
@@ -0,0 +1,6 @@
+- 2001-12-14 21:59:43.10 -5:30
+- 2001-12-14 21:59:43.10 +5:30
+- 2001-12-14 21:59:43.00101
+- 2001-12-14 21:59:43+1
+- 2001-12-14 21:59:43-1:30
+- 2005-07-08 17:35:04.517600
diff --git a/src/test/resources/pyyaml/timestamp.data b/src/test/resources/pyyaml/timestamp.data
new file mode 100644
index 00000000..7d214ce4
--- /dev/null
+++ b/src/test/resources/pyyaml/timestamp.data
@@ -0,0 +1,5 @@
+- 2001-12-15T02:59:43.1Z
+- 2001-12-14t21:59:43.10-05:00
+- 2001-12-14 21:59:43.10 -5
+- 2001-12-15 2:59:43.10
+- 2002-12-14
diff --git a/src/test/resources/pyyaml/unacceptable-key.loader-error b/src/test/resources/pyyaml/unacceptable-key.loader-error
new file mode 100644
index 00000000..d748e375
--- /dev/null
+++ b/src/test/resources/pyyaml/unacceptable-key.loader-error
@@ -0,0 +1,4 @@
+---
+? - foo
+ - bar
+: baz
diff --git a/src/test/resources/pyyaml/unclosed-bracket.loader-error b/src/test/resources/pyyaml/unclosed-bracket.loader-error
new file mode 100644
index 00000000..8c820777
--- /dev/null
+++ b/src/test/resources/pyyaml/unclosed-bracket.loader-error
@@ -0,0 +1,6 @@
+test:
+ - [ foo: bar
+# comment the rest of the stream to let the scanner detect the problem.
+# - baz
+#"we could have detected the unclosed bracket on the above line, but this would forbid such syntax as": {
+#}
diff --git a/src/test/resources/pyyaml/unclosed-quoted-scalar.loader-error b/src/test/resources/pyyaml/unclosed-quoted-scalar.loader-error
new file mode 100644
index 00000000..85374294
--- /dev/null
+++ b/src/test/resources/pyyaml/unclosed-quoted-scalar.loader-error
@@ -0,0 +1,2 @@
+'foo
+ bar
diff --git a/src/test/resources/pyyaml/undefined-anchor.loader-error b/src/test/resources/pyyaml/undefined-anchor.loader-error
new file mode 100644
index 00000000..94691032
--- /dev/null
+++ b/src/test/resources/pyyaml/undefined-anchor.loader-error
@@ -0,0 +1,3 @@
+- foo
+- &bar baz
+- *bat
diff --git a/src/test/resources/pyyaml/undefined-constructor.loader-error b/src/test/resources/pyyaml/undefined-constructor.loader-error
new file mode 100644
index 00000000..9a37ccc9
--- /dev/null
+++ b/src/test/resources/pyyaml/undefined-constructor.loader-error
@@ -0,0 +1 @@
+--- !foo bar
diff --git a/src/test/resources/pyyaml/undefined-tag-handle.loader-error b/src/test/resources/pyyaml/undefined-tag-handle.loader-error
new file mode 100644
index 00000000..82ba335c
--- /dev/null
+++ b/src/test/resources/pyyaml/undefined-tag-handle.loader-error
@@ -0,0 +1 @@
+--- !foo!bar baz
diff --git a/src/test/resources/pyyaml/unsupported-version.emitter-error b/src/test/resources/pyyaml/unsupported-version.emitter-error
new file mode 100644
index 00000000..f9c61976
--- /dev/null
+++ b/src/test/resources/pyyaml/unsupported-version.emitter-error
@@ -0,0 +1,5 @@
+- !StreamStart
+- !DocumentStart { version: [5,6] }
+- !Scalar { value: foo }
+- !DocumentEnd
+- !StreamEnd
diff --git a/src/test/resources/pyyaml/value.data b/src/test/resources/pyyaml/value.data
new file mode 100644
index 00000000..c5b7680c
--- /dev/null
+++ b/src/test/resources/pyyaml/value.data
@@ -0,0 +1 @@
+- =
diff --git a/src/test/resources/pyyaml/yaml.data b/src/test/resources/pyyaml/yaml.data
new file mode 100644
index 00000000..a4bb3f8e
--- /dev/null
+++ b/src/test/resources/pyyaml/yaml.data
@@ -0,0 +1,3 @@
+- !!yaml '!'
+- !!yaml '&'
+- !!yaml '*'
diff --git a/src/test/resources/reader/unicode-16be.txt b/src/test/resources/reader/unicode-16be.txt
new file mode 100644
index 00000000..18e8f256
--- /dev/null
+++ b/src/test/resources/reader/unicode-16be.txt
Binary files differ
diff --git a/src/test/resources/reader/unicode-16le.txt b/src/test/resources/reader/unicode-16le.txt
new file mode 100644
index 00000000..2f845860
--- /dev/null
+++ b/src/test/resources/reader/unicode-16le.txt
Binary files differ
diff --git a/src/test/resources/reader/utf-8.txt b/src/test/resources/reader/utf-8.txt
new file mode 100644
index 00000000..b0540d22
--- /dev/null
+++ b/src/test/resources/reader/utf-8.txt
@@ -0,0 +1 @@
+test \ No newline at end of file
diff --git a/src/test/resources/specification/example2_1.yaml b/src/test/resources/specification/example2_1.yaml
new file mode 100644
index 00000000..3cb7d7a6
--- /dev/null
+++ b/src/test/resources/specification/example2_1.yaml
@@ -0,0 +1,3 @@
+- Mark McGwire
+- Sammy Sosa
+- Ken Griffey
diff --git a/src/test/resources/specification/example2_10.yaml b/src/test/resources/specification/example2_10.yaml
new file mode 100644
index 00000000..f9e23baa
--- /dev/null
+++ b/src/test/resources/specification/example2_10.yaml
@@ -0,0 +1,8 @@
+---
+hr:
+ - Mark McGwire
+ # Following node labeled SS
+ - &SS Sammy Sosa
+rbi:
+ - *SS # Subsequent occurrence
+ - Ken Griffey
diff --git a/src/test/resources/specification/example2_11.yaml b/src/test/resources/specification/example2_11.yaml
new file mode 100644
index 00000000..bc991779
--- /dev/null
+++ b/src/test/resources/specification/example2_11.yaml
@@ -0,0 +1,9 @@
+? - Detroit Tigers
+ - Chicago cubs
+:
+ - 2001-07-23
+
+? [ New York Yankees,
+ Atlanta Braves ]
+: [ 2001-07-02, 2001-08-12,
+ 2001-08-14 ]
diff --git a/src/test/resources/specification/example2_12.yaml b/src/test/resources/specification/example2_12.yaml
new file mode 100644
index 00000000..6c120ac5
--- /dev/null
+++ b/src/test/resources/specification/example2_12.yaml
@@ -0,0 +1,8 @@
+---
+# products purchased
+- item : Super Hoop
+ quantity: 1
+- item : Basketball
+ quantity: 4
+- item : Big Shoes
+ quantity: 1
diff --git a/src/test/resources/specification/example2_13.yaml b/src/test/resources/specification/example2_13.yaml
new file mode 100644
index 00000000..e9276385
--- /dev/null
+++ b/src/test/resources/specification/example2_13.yaml
@@ -0,0 +1,4 @@
+# ASCII Art
+--- |
+ \//||\/||
+ // || ||__
diff --git a/src/test/resources/specification/example2_14.yaml b/src/test/resources/specification/example2_14.yaml
new file mode 100644
index 00000000..f39eb533
--- /dev/null
+++ b/src/test/resources/specification/example2_14.yaml
@@ -0,0 +1,4 @@
+---
+ Mark McGwire's
+ year was crippled
+ by a knee injury.
diff --git a/src/test/resources/specification/example2_15.yaml b/src/test/resources/specification/example2_15.yaml
new file mode 100644
index 00000000..fc92a53e
--- /dev/null
+++ b/src/test/resources/specification/example2_15.yaml
@@ -0,0 +1,8 @@
+>
+ Sammy Sosa completed another
+ fine season with great stats.
+
+ 63 Home Runs
+ 0.288 Batting Average
+
+ What a year!
diff --git a/src/test/resources/specification/example2_16.yaml b/src/test/resources/specification/example2_16.yaml
new file mode 100644
index 00000000..2e7ea487
--- /dev/null
+++ b/src/test/resources/specification/example2_16.yaml
@@ -0,0 +1,7 @@
+name: Mark McGwire
+accomplishment: >
+ Mark set a major league
+ home run record in 1998.
+stats: |
+ 65 Home Runs
+ 0.278 Batting Average
diff --git a/src/test/resources/specification/example2_17.yaml b/src/test/resources/specification/example2_17.yaml
new file mode 100644
index 00000000..592d4ae3
--- /dev/null
+++ b/src/test/resources/specification/example2_17.yaml
@@ -0,0 +1,7 @@
+unicode: "Sosa did fine.\u263A"
+control: "\b1998\t1999\t2000\n"
+hexesc: "\x0D\x0A is \r\n"
+
+single: '"Howdy!" he cried.'
+quoted: ' # not a ''comment''.'
+tie-fighter: '|\-*-/|'
diff --git a/src/test/resources/specification/example2_17_control.yaml b/src/test/resources/specification/example2_17_control.yaml
new file mode 100644
index 00000000..b8447d9c
--- /dev/null
+++ b/src/test/resources/specification/example2_17_control.yaml
@@ -0,0 +1,2 @@
+control: "\b1998\t1999\t2000\n"
+
diff --git a/src/test/resources/specification/example2_17_hexesc.yaml b/src/test/resources/specification/example2_17_hexesc.yaml
new file mode 100644
index 00000000..c3235305
--- /dev/null
+++ b/src/test/resources/specification/example2_17_hexesc.yaml
@@ -0,0 +1,2 @@
+hexesc: "\x0D\x0A is \r\n"
+
diff --git a/src/test/resources/specification/example2_17_quoted.yaml b/src/test/resources/specification/example2_17_quoted.yaml
new file mode 100644
index 00000000..8e7ca05b
--- /dev/null
+++ b/src/test/resources/specification/example2_17_quoted.yaml
@@ -0,0 +1,2 @@
+quoted: ' # not a ''comment''.'
+
diff --git a/src/test/resources/specification/example2_17_single.yaml b/src/test/resources/specification/example2_17_single.yaml
new file mode 100644
index 00000000..8f69b6cb
--- /dev/null
+++ b/src/test/resources/specification/example2_17_single.yaml
@@ -0,0 +1 @@
+single: '"Howdy!" he cried.'
diff --git a/src/test/resources/specification/example2_17_tie_fighter.yaml b/src/test/resources/specification/example2_17_tie_fighter.yaml
new file mode 100644
index 00000000..3d3928f4
--- /dev/null
+++ b/src/test/resources/specification/example2_17_tie_fighter.yaml
@@ -0,0 +1 @@
+tie-fighter: '|\-*-/|'
diff --git a/src/test/resources/specification/example2_17_unicode.yaml b/src/test/resources/specification/example2_17_unicode.yaml
new file mode 100644
index 00000000..60ec8085
--- /dev/null
+++ b/src/test/resources/specification/example2_17_unicode.yaml
@@ -0,0 +1,2 @@
+unicode: "Sosa did fine.\u263A"
+
diff --git a/src/test/resources/specification/example2_18.yaml b/src/test/resources/specification/example2_18.yaml
new file mode 100644
index 00000000..76fe0d26
--- /dev/null
+++ b/src/test/resources/specification/example2_18.yaml
@@ -0,0 +1,6 @@
+plain:
+ This unquoted scalar
+ spans many lines.
+
+quoted: "So does this
+ quoted scalar.\n"
diff --git a/src/test/resources/specification/example2_19.yaml b/src/test/resources/specification/example2_19.yaml
new file mode 100644
index 00000000..4a1c0700
--- /dev/null
+++ b/src/test/resources/specification/example2_19.yaml
@@ -0,0 +1,5 @@
+canonical: 12345
+decimal: +12_345
+sexagesimal: 3:25:45
+octal: 014
+hexadecimal: 0xC
diff --git a/src/test/resources/specification/example2_2.yaml b/src/test/resources/specification/example2_2.yaml
new file mode 100644
index 00000000..efd138d5
--- /dev/null
+++ b/src/test/resources/specification/example2_2.yaml
@@ -0,0 +1,3 @@
+hr: 65 # Home runs
+avg: 0.278 # Batting average
+rbi: 147 # Runs Batted In
diff --git a/src/test/resources/specification/example2_20.yaml b/src/test/resources/specification/example2_20.yaml
new file mode 100644
index 00000000..ceb1fd0d
--- /dev/null
+++ b/src/test/resources/specification/example2_20.yaml
@@ -0,0 +1,6 @@
+canonical: 1.23015e+3
+exponential: 12.3015e+02
+sexagesimal: 20:30.15
+fixed: 1_230.15
+negative infinity: -.inf
+not a number: .NaN
diff --git a/src/test/resources/specification/example2_21.yaml b/src/test/resources/specification/example2_21.yaml
new file mode 100644
index 00000000..d017affe
--- /dev/null
+++ b/src/test/resources/specification/example2_21.yaml
@@ -0,0 +1,4 @@
+null: ~
+true: yes
+false: no
+string: '12345'
diff --git a/src/test/resources/specification/example2_22.yaml b/src/test/resources/specification/example2_22.yaml
new file mode 100644
index 00000000..d4781f74
--- /dev/null
+++ b/src/test/resources/specification/example2_22.yaml
@@ -0,0 +1,4 @@
+canonical: 2001-12-15T02:59:43.1Z
+iso8601: 2001-12-14t21:59:43.10-05:00
+spaced: 2001-12-14 21:59:43.10 -5
+date: 2002-12-14
diff --git a/src/test/resources/specification/example2_23.yaml b/src/test/resources/specification/example2_23.yaml
new file mode 100644
index 00000000..310d4723
--- /dev/null
+++ b/src/test/resources/specification/example2_23.yaml
@@ -0,0 +1,14 @@
+---
+not-date: !!str 2002-04-28
+
+picture: !!binary "\
+ R0lGODlhDAAMAIQAAP//9/X\
+ 17unp5WZmZgAAAOfn515eXv\
+ Pz7Y6OjuDg4J+fn5OTk6enp\
+ 56enmleECcgggoBADs="
+
+application specific tag: !something |
+ The semantics of the tag
+ above may be different for
+ different documents.
+
diff --git a/src/test/resources/specification/example2_23_application.yaml b/src/test/resources/specification/example2_23_application.yaml
new file mode 100644
index 00000000..a77e4ef2
--- /dev/null
+++ b/src/test/resources/specification/example2_23_application.yaml
@@ -0,0 +1,5 @@
+---
+application specific tag: !something |
+ The semantics of the tag
+ above may be different for
+ different documents.
diff --git a/src/test/resources/specification/example2_23_non_date.yaml b/src/test/resources/specification/example2_23_non_date.yaml
new file mode 100644
index 00000000..58a6a327
--- /dev/null
+++ b/src/test/resources/specification/example2_23_non_date.yaml
@@ -0,0 +1,3 @@
+---
+not-date: !!str 2002-04-28
+
diff --git a/src/test/resources/specification/example2_23_picture.yaml b/src/test/resources/specification/example2_23_picture.yaml
new file mode 100644
index 00000000..1229d324
--- /dev/null
+++ b/src/test/resources/specification/example2_23_picture.yaml
@@ -0,0 +1,9 @@
+---
+picture: !!binary "\
+ R0lGODlhDAAMAIQAAP//9/X\
+ 17unp5WZmZgAAAOfn515eXv\
+ Pz7Y6OjuDg4J+fn5OTk6enp\
+ 56enmleECcgggoBADs="
+
+
+ \ No newline at end of file
diff --git a/src/test/resources/specification/example2_24.yaml b/src/test/resources/specification/example2_24.yaml
new file mode 100644
index 00000000..d97247ff
--- /dev/null
+++ b/src/test/resources/specification/example2_24.yaml
@@ -0,0 +1,14 @@
+%TAG ! tag:clarkevans.com,2002:
+--- !shape
+ # Use the ! handle for presenting
+ # tag:clarkevans.com,2002:circle
+- !circle
+ center: &ORIGIN {x: 73, y: 129}
+ radius: 7
+- !line
+ start: *ORIGIN
+ finish: { x: 89, y: 102 }
+- !label
+ start: *ORIGIN
+ color: 0xFFEEBB
+ text: Pretty vector drawing.
diff --git a/src/test/resources/specification/example2_24_dumped.yaml b/src/test/resources/specification/example2_24_dumped.yaml
new file mode 100644
index 00000000..f7e97662
--- /dev/null
+++ b/src/test/resources/specification/example2_24_dumped.yaml
@@ -0,0 +1,11 @@
+!shape
+- !circle
+ center: &id001 {x: 73, y: 129}
+ radius: 7
+- !line
+ finish: {x: 89, y: 102}
+ start: *id001
+- !label
+ color: 0xFFEEBB
+ start: *id001
+ text: Pretty vector drawing. \ No newline at end of file
diff --git a/src/test/resources/specification/example2_25.yaml b/src/test/resources/specification/example2_25.yaml
new file mode 100644
index 00000000..be58da2e
--- /dev/null
+++ b/src/test/resources/specification/example2_25.yaml
@@ -0,0 +1,7 @@
+# sets are represented as a
+# mapping where each key is
+# associated with the empty string
+--- !!set
+? Mark McGwire
+? Sammy Sosa
+? Ken Griff
diff --git a/src/test/resources/specification/example2_26.yaml b/src/test/resources/specification/example2_26.yaml
new file mode 100644
index 00000000..0a70a642
--- /dev/null
+++ b/src/test/resources/specification/example2_26.yaml
@@ -0,0 +1,7 @@
+# ordered maps are represented as
+# a sequence of mappings, with
+# each mapping having one key
+--- !!omap
+- Mark McGwire: 65
+- Sammy Sosa: 63
+- Ken Griffy: 58
diff --git a/src/test/resources/specification/example2_27.yaml b/src/test/resources/specification/example2_27.yaml
new file mode 100644
index 00000000..8eda5e0f
--- /dev/null
+++ b/src/test/resources/specification/example2_27.yaml
@@ -0,0 +1,29 @@
+--- !<tag:clarkevans.com,2002:invoice>
+invoice: 34843
+date : 2001-01-23
+billTo: &id001
+ given : Chris
+ family : Dumars
+ address:
+ lines: |
+ 458 Walkman Dr.
+ Suite #292
+ city : Royal Oak
+ state : MI
+ postal : 48046
+shipTo: *id001
+product:
+ - sku : BL394D
+ quantity : 4
+ description : Basketball
+ price : 450.00
+ - sku : BL4438H
+ quantity : 1
+ description : Super Hoop
+ price : 2392.00
+tax : 251.42
+total: 4443.52
+comments:
+ Late afternoon is best.
+ Backup contact is Nancy
+ Billsmer @ 338-4338.
diff --git a/src/test/resources/specification/example2_27_dumped.yaml b/src/test/resources/specification/example2_27_dumped.yaml
new file mode 100644
index 00000000..d0f22ac7
--- /dev/null
+++ b/src/test/resources/specification/example2_27_dumped.yaml
@@ -0,0 +1,18 @@
+!!org.yaml.snakeyaml.Invoice
+billTo: &id001
+ address: {city: Royal Oak, lines: '458 Walkman Dr.
+
+ Suite #292
+
+ ', postal: '48046', state: MI}
+ family: Dumars
+ given: Chris
+comments: Late afternoon is best. Backup contact is Nancy Billsmer @ 338-4338.
+date: '2001-01-23'
+invoice: 34843
+product:
+- {sku: BL394D, quantity: 4, description: Basketball, price: 450.0}
+- {sku: BL4438H, quantity: 1, description: Super Hoop, price: 2392.0}
+shipTo: *id001
+tax: 251.42
+total: 4443.52 \ No newline at end of file
diff --git a/src/test/resources/specification/example2_28.yaml b/src/test/resources/specification/example2_28.yaml
new file mode 100644
index 00000000..5880ac3a
--- /dev/null
+++ b/src/test/resources/specification/example2_28.yaml
@@ -0,0 +1,29 @@
+---
+Time: 2001-11-23 15:01:42 -5
+User: ed
+Warning:
+ This is an error message
+ for the log file
+---
+Time: 2001-11-23 15:02:31 -5
+User: ed
+Warning:
+ A slightly different error
+ message.
+---
+Date: 2001-11-23 15:03:17 -5
+User: ed
+Fatal:
+ Unknown variable "bar"
+Stack:
+ - file: TopClass.py
+ line: 23
+ code: |
+ x = MoreObject("345\n")
+ - file: MoreClass.py
+ line: 58
+ code: |-
+ foo = bar
+
+
+
diff --git a/src/test/resources/specification/example2_3.yaml b/src/test/resources/specification/example2_3.yaml
new file mode 100644
index 00000000..e0429fa0
--- /dev/null
+++ b/src/test/resources/specification/example2_3.yaml
@@ -0,0 +1,8 @@
+american:
+ - Boston Red Sox
+ - Detroit Tigers
+ - New York Yankees
+national:
+ - New York Mets
+ - Chicago Cubs
+ - Atlanta Braves \ No newline at end of file
diff --git a/src/test/resources/specification/example2_4.yaml b/src/test/resources/specification/example2_4.yaml
new file mode 100644
index 00000000..9bfb6cc9
--- /dev/null
+++ b/src/test/resources/specification/example2_4.yaml
@@ -0,0 +1,8 @@
+-
+ name: Mark McGwire
+ hr: 65
+ avg: 0.278
+-
+ name: Sammy Sosa
+ hr: 63
+ avg: 0.288
diff --git a/src/test/resources/specification/example2_5.yaml b/src/test/resources/specification/example2_5.yaml
new file mode 100644
index 00000000..260ce2dc
--- /dev/null
+++ b/src/test/resources/specification/example2_5.yaml
@@ -0,0 +1,3 @@
+- [name , hr, avg ]
+- [Mark McGwire, 65, 0.278]
+- [Sammy Sosa , 63, 0.288]
diff --git a/src/test/resources/specification/example2_6.yaml b/src/test/resources/specification/example2_6.yaml
new file mode 100644
index 00000000..f1a3c1ef
--- /dev/null
+++ b/src/test/resources/specification/example2_6.yaml
@@ -0,0 +1,5 @@
+Mark McGwire: {hr: 65, avg: 0.278}
+Sammy Sosa: {
+ hr: 63,
+ avg: 0.288
+ }
diff --git a/src/test/resources/specification/example2_7.yaml b/src/test/resources/specification/example2_7.yaml
new file mode 100644
index 00000000..1ea21489
--- /dev/null
+++ b/src/test/resources/specification/example2_7.yaml
@@ -0,0 +1,10 @@
+# Ranking of 1998 home runs
+---
+- Mark McGwire
+- Sammy Sosa
+- Ken Griffey
+
+# Team ranking
+---
+- Chicago Cubs
+- St Louis Cardinals
diff --git a/src/test/resources/specification/example2_8.yaml b/src/test/resources/specification/example2_8.yaml
new file mode 100644
index 00000000..4c286c37
--- /dev/null
+++ b/src/test/resources/specification/example2_8.yaml
@@ -0,0 +1,10 @@
+---
+time: 20:03:20
+player: Sammy Sosa
+action: strike (miss)
+...
+---
+time: 20:03:47
+player: Sammy Sosa
+action: grand slam
+...
diff --git a/src/test/resources/specification/example2_9.yaml b/src/test/resources/specification/example2_9.yaml
new file mode 100644
index 00000000..21c27047
--- /dev/null
+++ b/src/test/resources/specification/example2_9.yaml
@@ -0,0 +1,8 @@
+---
+hr: # 1998 hr ranking
+ - Mark McGwire
+ - Sammy Sosa
+rbi:
+ # 1998 rbi ranking
+ - Sammy Sosa
+ - Ken Griffey
diff --git a/src/test/resources/specification/types/map.yaml b/src/test/resources/specification/types/map.yaml
new file mode 100644
index 00000000..7e57a65e
--- /dev/null
+++ b/src/test/resources/specification/types/map.yaml
@@ -0,0 +1,6 @@
+# Unordered set of key: value pairs.
+Block style: !!map
+ Clark : Evans
+ Brian : Ingerson
+ Oren : Ben-Kiki
+Flow style: !!map { Clark: Evans, Brian: Ingerson, Oren: Ben-Kiki }
diff --git a/src/test/resources/specification/types/map_mixed_tags.yaml b/src/test/resources/specification/types/map_mixed_tags.yaml
new file mode 100644
index 00000000..ba1b5e09
--- /dev/null
+++ b/src/test/resources/specification/types/map_mixed_tags.yaml
@@ -0,0 +1,6 @@
+# Unordered set of key: value pairs.
+Block style: !<tag:yaml.org,2002:map>
+ Clark : Evans
+ Brian : Ingerson
+ Oren : Ben-Kiki
+Flow style: { Clark: Evans, Brian: Ingerson, Oren: Ben-Kiki }
diff --git a/src/test/resources/specification/types/merge.yaml b/src/test/resources/specification/types/merge.yaml
new file mode 100644
index 00000000..00f189ab
--- /dev/null
+++ b/src/test/resources/specification/types/merge.yaml
@@ -0,0 +1,27 @@
+---
+- &CENTER { x: 1, y: 2 }
+- &LEFT { x: 0, y: 2 }
+- &BIG { r: 10 }
+- &SMALL { r: 1 }
+
+# All the following maps are equal:
+
+- # Explicit keys
+ x: 1
+ y: 2
+ r: 10
+ label: center/big
+
+- # Merge one map
+ << : *CENTER
+ r: 10
+ label: center/big
+
+- # Merge multiple maps
+ << : [ *CENTER, *BIG ]
+ label: center/big
+
+- # Override
+ << : [ *BIG, *LEFT, *SMALL ]
+ x: 1
+ label: center/big
diff --git a/src/test/resources/specification/types/omap.yaml b/src/test/resources/specification/types/omap.yaml
new file mode 100644
index 00000000..5e0a8123
--- /dev/null
+++ b/src/test/resources/specification/types/omap.yaml
@@ -0,0 +1,8 @@
+# Explicitly typed ordered map (dictionary).
+Bestiary: !!omap
+ - aardvark: African pig-like ant eater. Ugly.
+ - anteater: South-American ant eater. Two species.
+ - anaconda: South-American constrictor snake. Scaly.
+ # Etc.
+# Flow style
+Numbers: !!omap [ one: 1, two: 2, three : 3 ]
diff --git a/src/test/resources/specification/types/pairs.yaml b/src/test/resources/specification/types/pairs.yaml
new file mode 100644
index 00000000..34acf770
--- /dev/null
+++ b/src/test/resources/specification/types/pairs.yaml
@@ -0,0 +1,7 @@
+# Explicitly typed pairs.
+Block tasks: !!pairs
+ - meeting: with team.
+ - meeting: with boss.
+ - break: lunch.
+ - meeting: with client.
+Flow tasks: !!pairs [ meeting: with team, meeting: with boss ]
diff --git a/src/test/resources/specification/types/seq.yaml b/src/test/resources/specification/types/seq.yaml
new file mode 100644
index 00000000..dd690e2d
--- /dev/null
+++ b/src/test/resources/specification/types/seq.yaml
@@ -0,0 +1,14 @@
+# Ordered sequence of nodes
+Block style: !!seq
+- Mercury # Rotates - no light/dark sides.
+- Venus # Deadliest. Aptly named.
+- Earth # Mostly dirt.
+- Mars # Seems empty.
+- Jupiter # The king.
+- Saturn # Pretty.
+- Uranus # Where the sun hardly shines.
+- Neptune # Boring. No rings.
+- Pluto # You call this a planet?
+Flow style: !!seq [ Mercury, Venus, Earth, Mars, # Rocks
+ Jupiter, Saturn, Uranus, Neptune, # Gas
+ Pluto ] # Overrated
diff --git a/src/test/resources/specification/types/set.yaml b/src/test/resources/specification/types/set.yaml
new file mode 100644
index 00000000..19406eb0
--- /dev/null
+++ b/src/test/resources/specification/types/set.yaml
@@ -0,0 +1,7 @@
+# Explicitly typed set.
+baseball players: !!set
+ ? Mark McGwire
+ ? Sammy Sosa
+ ? Ken Griffey
+# Flow style
+baseball teams: !!set { Boston Red Sox, Detroit Tigers, New York Yankees }
diff --git a/src/test/resources/specification/types/v.yaml b/src/test/resources/specification/types/v.yaml
new file mode 100644
index 00000000..0fdc8fb7
--- /dev/null
+++ b/src/test/resources/specification/types/v.yaml
@@ -0,0 +1,4 @@
+--- # New schema
+link with:
+ - = : library1.dll
+ version: 1.2
diff --git a/src/test/resources/specification/types/value.yaml b/src/test/resources/specification/types/value.yaml
new file mode 100644
index 00000000..8f83a6e2
--- /dev/null
+++ b/src/test/resources/specification/types/value.yaml
@@ -0,0 +1,10 @@
+--- # Old schema
+link with:
+ - library1.dll
+ - library2.dll
+--- # New schema
+link with:
+ - = : library1.dll
+ version: 1.2
+ - = : library2.dll
+ version: 2.3