Merge commit 'cce31f6de8fea06821a8b57a9c0d2c687c8161f5' into nyc-dev
Bug: 27552463
Change-Id: Ieda4ab70675662ca687ac4a2e4f59f30034ffdca
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..e0a8909
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,9 @@
+
+
+.classpath
+.project
+.settings/
+target/
+bin/
+
+
diff --git a/.hgeol b/.hgeol
new file mode 100644
index 0000000..5bd567d
--- /dev/null
+++ b/.hgeol
@@ -0,0 +1,8 @@
+[patterns]
+**.java = LF
+**.txt = LF
+**.xml = LF
+**.yaml = LF
+**.yml = LF
+**.data = LF
+**.canonical = LF
diff --git a/.hgignore b/.hgignore
new file mode 100644
index 0000000..2f0116d
--- /dev/null
+++ b/.hgignore
@@ -0,0 +1,12 @@
+syntax: regexp
+^target$
+^bin$
+^\.settings$
+^\.project$
+^\.classpath$
+
+^\.idea$
+snakeyaml.iml
+snakeyaml.ipr
+snakeyaml.iws
+
diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml
new file mode 100644
index 0000000..e3d7780
--- /dev/null
+++ b/.mvn/extensions.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<extensions>
+ <extension>
+ <groupId>io.takari.polyglot</groupId>
+ <artifactId>polyglot-yaml</artifactId>
+ <version>0.1.12</version>
+ </extension>
+</extensions>
diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar
new file mode 100644
index 0000000..5fd4d50
--- /dev/null
+++ b/.mvn/wrapper/maven-wrapper.jar
Binary files differ
diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties
new file mode 100644
index 0000000..ac516e2
--- /dev/null
+++ b/.mvn/wrapper/maven-wrapper.properties
@@ -0,0 +1 @@
+distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.3.1/apache-maven-3.3.1-bin.zip
\ No newline at end of file
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 0000000..e91fdb1
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,59 @@
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+# Build support for snakeyaml within the Android Open Source Project
+# See https://source.android.com/source/building.html for more information
+#
+
+LOCAL_PATH := $(call my-dir)
+
+# List of all files that need to be patched (see src/patches/android)
+snakeyaml_need_patch_src_files := \
+ src/main/java/org/yaml/snakeyaml/extensions/compactnotation/CompactConstructor.java \
+ src/main/java/org/yaml/snakeyaml/constructor/Constructor.java \
+ src/main/java/org/yaml/snakeyaml/introspector/PropertyUtils.java \
+ src/main/java/org/yaml/snakeyaml/representer/Representer.java
+# List of all files that are unsupported on android (see pom.xml)
+snakeyaml_unsupported_android_src_files := \
+ src/main/java/org/yaml/snakeyaml/introspector/MethodProperty.java
+snakeyaml_src_files_unfiltered := $(call all-java-files-under, src/main)
+# We omit the list of files that need to be patched because those are included by LOCAL_GENERATED_SOURCES instead.
+snakeyaml_src_files := $(filter-out $(snakeyaml_need_patch_src_files) $(snakeyaml_unsupported_android_src_files),$(snakeyaml_src_files_unfiltered))
+
+# Host-side Java build
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(snakeyaml_src_files_unfiltered)
+LOCAL_MODULE := snakeyaml-host
+include $(BUILD_HOST_JAVA_LIBRARY)
+
+# Host-side Dalvik build
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(snakeyaml_src_files)
+LOCAL_MODULE := snakeyaml-hostdex
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+# Apply all of the Android patches in src/patches/android by running patch-android-src script on them.
+intermediates:= $(local-generated-sources-dir)
+GEN := $(addprefix $(intermediates)/, $(snakeyaml_need_patch_src_files)) # List of all files that need to be patched.
+$(GEN) : PRIVATE_PATH := $(LOCAL_PATH)
+$(GEN) : PRIVATE_CUSTOM_TOOL = $(PRIVATE_PATH)/patch-android-src $(PRIVATE_PATH)/ $< $@
+$(GEN): $(intermediates)/%.java : $(LOCAL_PATH)/%.java $(LOCAL_PATH)/patch-android-src
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+include $(BUILD_HOST_DALVIK_JAVA_LIBRARY)
+
+# TODO: Consider adding tests.
diff --git a/CleanSpec.mk b/CleanSpec.mk
new file mode 100644
index 0000000..7ace389
--- /dev/null
+++ b/CleanSpec.mk
@@ -0,0 +1,54 @@
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list. These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+# $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list. E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+
+# For example:
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+
+# Clean up generated code from snakeyaml-hostdex
+# (When removing a file from $(snakeyaml_need_patch_src_files),
+# make a rule similar to below to remove stale files from incremental builds).
+#
+# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/gen/JAVA_LIBRARIES/snakeyaml-hostdex_intermediates)/path/to/RemovedFile.java
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 0000000..d9a10c0
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,176 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
diff --git a/MODULE_LICENSE_APACHE2 b/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/MODULE_LICENSE_APACHE2
diff --git a/NOTICE b/NOTICE
new file mode 100644
index 0000000..d9a10c0
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1,176 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..b51464e
--- /dev/null
+++ b/README.md
@@ -0,0 +1,24 @@
+***The art of simplicity is a puzzle of complexity.***
+
+## Overview ##
+[YAML](http://yaml.org) is a data serialization format designed for human readability and interaction with scripting languages.
+
+SnakeYAML is a YAML processor for the Java Virtual Machine.
+
+## SnakeYAML features ##
+
+* a **complete** [YAML 1.1 processor](http://yaml.org/spec/1.1/current.html). 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 [YAML types repository](http://yaml.org/type/index.html).
+* relatively sensible error messages.
+
+## Info ##
+ * [Changes](https://bitbucket.org/asomov/snakeyaml/wiki/Changes)
+ * [Documentation](https://bitbucket.org/asomov/snakeyaml/wiki/Documentation)
+
+## Contribute ##
+* Mercurial DVCS is used to dance with the [source code](https://bitbucket.org/asomov/snakeyaml/src).
+* If you find a bug in SnakeYAML, please [file a bug report](https://bitbucket.org/asomov/snakeyaml/issues?status=new&status=open).
+* You may discuss SnakeYAML at
+[the mailing list](http://groups.google.com/group/snakeyaml-core).
\ No newline at end of file
diff --git a/README.version b/README.version
new file mode 100644
index 0000000..71ee1d2
--- /dev/null
+++ b/README.version
@@ -0,0 +1,4 @@
+URL: https://bitbucket.org/asomov/snakeyaml
+Version: hg id 29a091e21588
+BugComponent: 99142
+Owners: iam
diff --git a/docker-run-jdk6.sh b/docker-run-jdk6.sh
new file mode 100755
index 0000000..5904c90
--- /dev/null
+++ b/docker-run-jdk6.sh
@@ -0,0 +1,3 @@
+#!/usr/bin/env bash
+./docker-run.sh 6
+
diff --git a/docker-run-jdk7.sh b/docker-run-jdk7.sh
new file mode 100755
index 0000000..b2c9782
--- /dev/null
+++ b/docker-run-jdk7.sh
@@ -0,0 +1,4 @@
+#!/usr/bin/env bash
+./docker-run.sh 7
+
+
diff --git a/docker-run-jdk8.sh b/docker-run-jdk8.sh
new file mode 100755
index 0000000..aaf10f0
--- /dev/null
+++ b/docker-run-jdk8.sh
@@ -0,0 +1,4 @@
+#!/usr/bin/env bash
+./docker-run.sh 8
+
+
diff --git a/docker-run.sh b/docker-run.sh
new file mode 100755
index 0000000..3abaa88
--- /dev/null
+++ b/docker-run.sh
@@ -0,0 +1,16 @@
+#!/usr/bin/env bash
+if [ "$#" -ne 1 ]
+then
+ echo "Usage: docker-run.sh <JDK number> (number can be 6, 7, 8)"
+ exit 1
+fi
+
+docker run --rm -it \
+ -u `id -u`:`id -g` \
+ -v `pwd`:/work \
+ -v ~:/my-home \
+ -e "HOME=/my-home" \
+ -w /work \
+ maven:3-jdk-$1 \
+ mvn -Dmaven.repo.local=/my-home/.m2/repository clean test
+
diff --git a/mvnw b/mvnw
new file mode 100755
index 0000000..c67cd41
--- /dev/null
+++ b/mvnw
@@ -0,0 +1,234 @@
+#!/bin/sh
+# ----------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+# ----------------------------------------------------------------------------
+
+# ----------------------------------------------------------------------------
+# Maven2 Start Up Batch script
+#
+# Required ENV vars:
+# ------------------
+# JAVA_HOME - location of a JDK home dir
+#
+# Optional ENV vars
+# -----------------
+# M2_HOME - location of maven2's installed home dir
+# MAVEN_OPTS - parameters passed to the Java VM when running Maven
+# e.g. to debug Maven itself, use
+# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+# ----------------------------------------------------------------------------
+
+if [ -z "$MAVEN_SKIP_RC" ] ; then
+
+ if [ -f /etc/mavenrc ] ; then
+ . /etc/mavenrc
+ fi
+
+ if [ -f "$HOME/.mavenrc" ] ; then
+ . "$HOME/.mavenrc"
+ fi
+
+fi
+
+# OS specific support. $var _must_ be set to either true or false.
+cygwin=false;
+darwin=false;
+mingw=false
+case "`uname`" in
+ CYGWIN*) cygwin=true ;;
+ MINGW*) mingw=true;;
+ Darwin*) darwin=true
+ #
+ # Look for the Apple JDKs first to preserve the existing behaviour, and then look
+ # for the new JDKs provided by Oracle.
+ #
+ if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK ] ; then
+ #
+ # Apple JDKs
+ #
+ export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home
+ fi
+
+ if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Java/JavaVirtualMachines/CurrentJDK ] ; then
+ #
+ # Apple JDKs
+ #
+ export JAVA_HOME=/System/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home
+ fi
+
+ if [ -z "$JAVA_HOME" ] && [ -L "/Library/Java/JavaVirtualMachines/CurrentJDK" ] ; then
+ #
+ # Oracle JDKs
+ #
+ export JAVA_HOME=/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home
+ fi
+
+ if [ -z "$JAVA_HOME" ] && [ -x "/usr/libexec/java_home" ]; then
+ #
+ # Apple JDKs
+ #
+ export JAVA_HOME=`/usr/libexec/java_home`
+ fi
+ ;;
+esac
+
+if [ -z "$JAVA_HOME" ] ; then
+ if [ -r /etc/gentoo-release ] ; then
+ JAVA_HOME=`java-config --jre-home`
+ fi
+fi
+
+if [ -z "$M2_HOME" ] ; then
+ ## resolve links - $0 may be a link to maven's home
+ PRG="$0"
+
+ # need this for relative symlinks
+ while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG="`dirname "$PRG"`/$link"
+ fi
+ done
+
+ saveddir=`pwd`
+
+ M2_HOME=`dirname "$PRG"`/..
+
+ # make it fully qualified
+ M2_HOME=`cd "$M2_HOME" && pwd`
+
+ cd "$saveddir"
+ # echo Using m2 at $M2_HOME
+fi
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched
+if $cygwin ; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME=`cygpath --unix "$M2_HOME"`
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+ [ -n "$CLASSPATH" ] &&
+ CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
+fi
+
+# For Migwn, ensure paths are in UNIX format before anything is touched
+if $mingw ; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME="`(cd "$M2_HOME"; pwd)`"
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
+ # TODO classpath?
+fi
+
+if [ -z "$JAVA_HOME" ]; then
+ javaExecutable="`which javac`"
+ if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
+ # readlink(1) is not available as standard on Solaris 10.
+ readLink=`which readlink`
+ if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
+ if $darwin ; then
+ javaHome="`dirname \"$javaExecutable\"`"
+ javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
+ else
+ javaExecutable="`readlink -f \"$javaExecutable\"`"
+ fi
+ javaHome="`dirname \"$javaExecutable\"`"
+ javaHome=`expr "$javaHome" : '\(.*\)/bin'`
+ JAVA_HOME="$javaHome"
+ export JAVA_HOME
+ fi
+ fi
+fi
+
+if [ -z "$JAVACMD" ] ; then
+ if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ else
+ JAVACMD="`which java`"
+ fi
+fi
+
+if [ ! -x "$JAVACMD" ] ; then
+ echo "Error: JAVA_HOME is not defined correctly." >&2
+ echo " We cannot execute $JAVACMD" >&2
+ exit 1
+fi
+
+if [ -z "$JAVA_HOME" ] ; then
+ echo "Warning: JAVA_HOME environment variable is not set."
+fi
+
+CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME=`cygpath --path --windows "$M2_HOME"`
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
+ [ -n "$CLASSPATH" ] &&
+ CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
+fi
+
+# traverses directory structure from process work directory to filesystem root
+# first directory with .mvn subdirectory is considered project base directory
+find_maven_basedir() {
+ local basedir=$(pwd)
+ local wdir=$(pwd)
+ while [ "$wdir" != '/' ] ; do
+ wdir=$(cd "$wdir/.."; pwd)
+ if [ -d "$wdir"/.mvn ] ; then
+ basedir=$wdir
+ break
+ fi
+ done
+ echo "${basedir}"
+}
+
+# concatenates all lines of a file
+concat_lines() {
+ if [ -f "$1" ]; then
+ echo "$(tr -s '\n' ' ' < "$1")"
+ fi
+}
+
+export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-$(find_maven_basedir)}
+MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
+
+# Provide a "standardized" way to retrieve the CLI args that will
+# work with both Windows and non-Windows executions.
+MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
+export MAVEN_CMD_LINE_ARGS
+
+WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+exec "$JAVACMD" \
+ $MAVEN_OPTS \
+ -classpath "./.mvn/wrapper/maven-wrapper.jar" \
+ "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
+ ${WRAPPER_LAUNCHER} "$@"
+
diff --git a/mvnw.bat b/mvnw.bat
new file mode 100644
index 0000000..7ca42b9
--- /dev/null
+++ b/mvnw.bat
@@ -0,0 +1,177 @@
+@REM ----------------------------------------------------------------------------
+@REM Licensed to the Apache Software Foundation (ASF) under one
+@REM or more contributor license agreements. See the NOTICE file
+@REM distributed with this work for additional information
+@REM regarding copyright ownership. The ASF licenses this file
+@REM to you under the Apache License, Version 2.0 (the
+@REM "License"); you may not use this file except in compliance
+@REM with the License. You may obtain a copy of the License at
+@REM
+@REM http://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing,
+@REM software distributed under the License is distributed on an
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@REM KIND, either express or implied. See the License for the
+@REM specific language governing permissions and limitations
+@REM under the License.
+@REM ----------------------------------------------------------------------------
+
+@REM ----------------------------------------------------------------------------
+@REM Maven2 Start Up Batch script
+@REM
+@REM Required ENV vars:
+@REM JAVA_HOME - location of a JDK home dir
+@REM
+@REM Optional ENV vars
+@REM M2_HOME - location of maven2's installed home dir
+@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
+@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
+@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
+@REM e.g. to debug Maven itself, use
+@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+@REM ----------------------------------------------------------------------------
+
+@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
+@echo off
+@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
+@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
+
+@REM set %HOME% to equivalent of $HOME
+if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
+
+@REM Execute a user defined script before this one
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
+@REM check for pre script, once with legacy .bat ending and once with .cmd ending
+if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
+if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
+:skipRcPre
+
+@setlocal
+
+set ERROR_CODE=0
+
+@REM To isolate internal variables from possible post scripts, we use another setlocal
+@setlocal
+
+@REM ==== START VALIDATION ====
+if not "%JAVA_HOME%" == "" goto OkJHome
+
+echo.
+echo Error: JAVA_HOME not found in your environment. >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+:OkJHome
+if exist "%JAVA_HOME%\bin\java.exe" goto chkMHome
+
+echo.
+echo Error: JAVA_HOME is set to an invalid directory. >&2
+echo JAVA_HOME = "%JAVA_HOME%" >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+:chkMHome
+if not "%M2_HOME%"=="" goto valMHome
+
+SET "M2_HOME=%~dp0.."
+if not "%M2_HOME%"=="" goto valMHome
+
+echo.
+echo Error: M2_HOME not found in your environment. >&2
+echo Please set the M2_HOME variable in your environment to match the >&2
+echo location of the Maven installation. >&2
+echo.
+goto error
+
+:valMHome
+
+:stripMHome
+if not "_%M2_HOME:~-1%"=="_\" goto checkMCmd
+set "M2_HOME=%M2_HOME:~0,-1%"
+goto stripMHome
+
+:checkMCmd
+if exist "%M2_HOME%\bin\mvn.cmd" goto init
+
+echo.
+echo Error: M2_HOME is set to an invalid directory. >&2
+echo M2_HOME = "%M2_HOME%" >&2
+echo Please set the M2_HOME variable in your environment to match the >&2
+echo location of the Maven installation >&2
+echo.
+goto error
+@REM ==== END VALIDATION ====
+
+:init
+
+set MAVEN_CMD_LINE_ARGS=%*
+
+@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
+@REM Fallback to current working directory if not found.
+
+set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
+IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
+
+set EXEC_DIR=%CD%
+set WDIR=%EXEC_DIR%
+:findBaseDir
+IF EXIST "%WDIR%"\.mvn goto baseDirFound
+cd ..
+IF "%WDIR%"=="%CD%" goto baseDirNotFound
+set WDIR=%CD%
+goto findBaseDir
+
+:baseDirFound
+set MAVEN_PROJECTBASEDIR=%WDIR%
+cd "%EXEC_DIR%"
+goto endDetectBaseDir
+
+:baseDirNotFound
+set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
+cd "%EXEC_DIR%"
+
+:endDetectBaseDir
+
+IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
+
+@setlocal EnableExtensions EnableDelayedExpansion
+for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
+@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
+
+:endReadAdditionalConfig
+
+SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
+
+for %%i in ("%M2_HOME%"\boot\plexus-classworlds-*) do set CLASSWORLDS_JAR="%%i"
+
+set WRAPPER_JAR="".\.mvn\wrapper\maven-wrapper.jar""
+set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.home=%M2_HOME%" "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CMD_LINE_ARGS%
+if ERRORLEVEL 1 goto error
+goto end
+
+:error
+set ERROR_CODE=1
+
+:end
+@endlocal & set ERROR_CODE=%ERROR_CODE%
+
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
+@REM check for post script, once with legacy .bat ending and once with .cmd ending
+if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
+if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
+:skipRcPost
+
+@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
+if "%MAVEN_BATCH_PAUSE%" == "on" pause
+
+if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
+
+exit /B %ERROR_CODE%
diff --git a/patch-android-src b/patch-android-src
new file mode 100755
index 0000000..dacf1fc
--- /dev/null
+++ b/patch-android-src
@@ -0,0 +1,91 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# Given a source file, for example Constructor.java, find the patch file for it and apply it.
+# Patch is applied to a copy (as opposed to in-place), for example into a build artifact location.
+
+if [[ $# -lt 3 ]]; then
+ echo "Usage: $(basename $0) <src-file-prefix> <src-file> <dst-file>"
+ exit 1
+fi
+
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+ANDROID_PATCHES_DIR="$DIR/src/patches/android"
+
+src_file_prefix="$1"
+src_file="$2"
+src_file_with_prefix="$2"
+dst_file="$3"
+dst_dir="$(dirname "$dst_file")"
+
+# Sanity checking
+
+if ! [[ -d $ANDROID_PATCHES_DIR ]]; then
+ echo "FATAL: Android patch directory $ANDROID_PATCHES_DIR does not exist." >&2
+ exit 1
+fi
+
+if ! [[ $src_file == $src_file_prefix* ]]; then
+ echo "$src_file_prefix is not a valid prefix of $src_file" >&2
+ exit 1
+fi
+
+if ! [[ -f $src_file ]]; then
+ echo "Source file $src_file does not exist." >&2
+ exit 1
+fi
+
+# Remove the src file prefix, giving us the correct grep target for the .patch files.
+src_file="${src_file#$src_file_prefix}"
+
+patch_file_src=$(grep --files-with-matches -R "diff --git a/$src_file" "$ANDROID_PATCHES_DIR")
+if [[ $? -ne 0 ]]; then
+ echo "Error: Could not find a corresponding .patch file for $src_file" >&2
+ exit 1
+fi
+
+# Parse the source file from the .patch file (assumes exactly one file diff per .patch file)
+src_file_check=$(cat "$patch_file_src" | grep "diff --git a/" | sed -e "s:diff --git a\/::g" | sed -e "s: b\/.*::g")
+
+
+if ! [[ -f $patch_file_src ]]; then
+ echo "Patch file $patch_file_src does not exist." >&2
+ exit 1
+fi
+
+if ! cat "$patch_file_src" | grep "diff --git a/" > /dev/null; then
+ echo "File $patch_file_src is not a valid diff file" >&2
+ exit 1
+fi
+
+if [[ $src_file != $src_file_check ]]; then
+ echo "Check-fail: $src_file was not same as found in patch file ($src_file_check)" >&2
+ exit 1
+fi
+
+set -e
+
+# Copy the src file and then apply the patch to it.
+mkdir -p "$dst_dir"
+cp "$src_file_with_prefix" "$dst_file"
+if ! [[ -f "$dst_file" ]]; then
+ echo "File "$dst_file" does not exist; patching will fail" >&2
+ exit 1
+fi
+cd "$dst_dir"
+patch "$(basename "$dst_file")" "$patch_file_src"
+echo "Successfully applied patch $patch_file_src into copy of file $dst_file"
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..91886af
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,637 @@
+<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>org.yaml</groupId>
+ <artifactId>snakeyaml</artifactId>
+ <version>1.18-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <project.scm.id>bitbucket</project.scm.id>
+ <release.repo.url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</release.repo.url>
+ <snapshot.repo.url>https://oss.sonatype.org/content/repositories/snapshots/</snapshot.repo.url>
+ <maven.compiler.source>1.6</maven.compiler.source>
+ <maven.compiler.target>1.6</maven.compiler.target>
+ <maven.javadoc.failOnError>false</maven.javadoc.failOnError>
+ </properties>
+ <name>SnakeYAML</name>
+ <description>YAML 1.1 parser and emitter for Java</description>
+ <inceptionYear>2008</inceptionYear>
+ <url>http://www.snakeyaml.org</url>
+ <issueManagement>
+ <system>Bitbucket</system>
+ <url>https://bitbucket.org/asomov/snakeyaml/issues</url>
+ </issueManagement>
+ <!--ciManagement>
+ <system>jenkins</system>
+ <url>https://snakeyaml.ci.cloudbees.com/job/SnakeYAML/</url>
+ </ciManagement-->
+ <mailingLists>
+ <mailingList>
+ <name>SnakeYAML developers and users List</name>
+ <post>snakeyaml-core@googlegroups.com</post>
+ </mailingList>
+ </mailingLists>
+ <scm>
+ <connection>scm:hg:http://bitbucket.org/asomov/snakeyaml</connection>
+ <developerConnection>scm:hg:ssh://hg@bitbucket.org/asomov/snakeyaml</developerConnection>
+ <url>https://bitbucket.org/asomov/snakeyaml/src</url>
+ <tag>HEAD</tag>
+ </scm>
+ <licenses>
+ <license>
+ <name>Apache License, Version 2.0</name>
+ <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+ <distribution>repo</distribution>
+ </license>
+ </licenses>
+ <developers>
+ <developer>
+ <id>asomov</id>
+ <name>Andrey Somov</name>
+ <email>public.somov@gmail.com</email>
+ </developer>
+ <developer>
+ <id>maslovalex</id>
+ <name>Alexander Maslov</name>
+ <email>alexander.maslov@gmail.com</email>
+ </developer>
+ <developer>
+ <id>Jordan</id>
+ <name>Jordan Angold</name>
+ <email>jordanangold@gmail.com</email>
+ </developer>
+ </developers>
+ <prerequisites>
+ <maven>3.0.5</maven>
+ </prerequisites>
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.12</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring</artifactId>
+ <version>2.5.6</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.velocity</groupId>
+ <artifactId>velocity</artifactId>
+ <version>1.6.2</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>joda-time</groupId>
+ <artifactId>joda-time</artifactId>
+ <version>1.6</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ <distributionManagement>
+ <repository>
+ <id>sonatype-nexus-staging</id>
+ <name>Nexus Release Repository</name>
+ <url>${release.repo.url}</url>
+ </repository>
+ <snapshotRepository>
+ <id>sonatype-nexus-snapshots</id>
+ <name>Sonatype Nexus Snapshots</name>
+ <url>${snapshot.repo.url}</url>
+ <uniqueVersion>false</uniqueVersion>
+ </snapshotRepository>
+ </distributionManagement>
+ <build>
+ <testResources>
+ <testResource>
+ <directory>${basedir}/src/test/resources</directory>
+ <filtering>true</filtering>
+ </testResource>
+ </testResources>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <version>2.10.3</version>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-site-plugin</artifactId>
+ <version>3.5</version>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>3.5.1</version>
+ <configuration>
+ <source>${maven.compiler.source}</source>
+ <target>${maven.compiler.target}</target>
+ <encoding>${project.build.sourceEncoding}</encoding>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>2.19.1</version>
+ <configuration>
+ <argLine>-Xmx512m</argLine>
+ <includes>
+ <include>**/*Test.java</include>
+ </includes>
+ <excludes>
+ <exclude>**/StressTest.java</exclude>
+ <exclude>**/ParallelTest.java</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-eclipse-plugin</artifactId>
+ <version>2.10</version>
+ <configuration>
+ <buildOutputDirectory>bin</buildOutputDirectory>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>cobertura-maven-plugin</artifactId>
+ <version>2.7</version>
+ <configuration>
+ <check>
+ <totalBranchRate>80</totalBranchRate>
+ <totalLineRate>95</totalLineRate>
+ </check>
+ <formats>
+ <format>html</format>
+ <format>xml</format>
+ </formats>
+ <instrumentation>
+ <excludes>
+ <exclude>org/yaml/snakeyaml/external/**</exclude>
+ </excludes>
+ </instrumentation>
+ </configuration>
+ <executions>
+ <execution>
+ <goals>
+ <goal>clean</goal>
+ <goal>check</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-changes-plugin</artifactId>
+ <version>2.11</version>
+ <executions>
+ <execution>
+ <id>validate-changes</id>
+ <phase>pre-site</phase>
+ <goals>
+ <goal>changes-validate</goal>
+ </goals>
+ <configuration>
+ <failOnError>true</failOnError>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-source-plugin</artifactId>
+ <version>3.0.0</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <configuration>
+ <links>
+ <link>http://java.sun.com/javase/6/docs/api/</link>
+ </links>
+ </configuration>
+ <executions>
+ <execution>
+ <id>attach-javadocs</id>
+ <goals>
+ <goal>jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>com.mycila.maven-license-plugin</groupId>
+ <artifactId>maven-license-plugin</artifactId>
+ <version>1.10.b1</version>
+ <configuration>
+ <header>src/etc/header.txt</header>
+ <quiet>false</quiet>
+ <failIfMissing>true</failIfMissing>
+ <aggregate>false</aggregate>
+ <includes>
+ <include>src/**/*.java</include>
+ </includes>
+ <excludes>
+ <exclude>src/main/java/org/yaml/snakeyaml/external/**</exclude>
+ </excludes>
+ <useDefaultExcludes>true</useDefaultExcludes>
+ <useDefaultMapping>true</useDefaultMapping>
+ <strictCheck>true</strictCheck>
+ <encoding>UTF-8</encoding>
+ </configuration>
+ <executions>
+ <execution>
+ <phase>site</phase>
+ <goals>
+ <goal>format</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>3.0.1</version>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <_nouses>true</_nouses>
+ <Export-Package>
+ !org.yaml.snakeyaml.external*,
+ org.yaml.snakeyaml.*;version=${project.version}
+ </Export-Package>
+ <Bundle-RequiredExecutionEnvironment>J2SE-1.5</Bundle-RequiredExecutionEnvironment>
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-site-plugin</artifactId>
+ <version>3.4</version>
+ <executions>
+ <execution>
+ <id>attach-descriptor</id>
+ <goals>
+ <goal>attach-descriptor</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ <reporting>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-changes-plugin</artifactId>
+ <version>2.11</version>
+ <configuration>
+ <issueLinkTemplate>https://bitbucket.org/asomov/snakeyaml/issues/%ISSUE%</issueLinkTemplate>
+ </configuration>
+ <reportSets>
+ <reportSet>
+ <reports>
+ <report>changes-report</report>
+ </reports>
+ </reportSet>
+ </reportSets>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-report-plugin</artifactId>
+ <version>2.19.1</version>
+ <configuration>
+ <showSuccess>true</showSuccess>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>cobertura-maven-plugin</artifactId>
+ <version>2.6</version>
+ <configuration>
+ <formats>
+ <format>html</format>
+ <format>xml</format>
+ </formats>
+ </configuration>
+ </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>
+ <profiles>
+ <profile>
+ <id>toolchain</id>
+ <activation>
+ <file>
+ <exists>${user.home}/.m2/toolchains.xml</exists>
+ </file>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-toolchains-plugin</artifactId>
+ <version>1.1</version>
+ <executions>
+ <execution>
+ <phase>validate</phase>
+ <goals>
+ <goal>toolchain</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <toolchains>
+ <jdk>
+ <version>${maven.compiler.target}</version>
+ </jdk>
+ </toolchains>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ <profile>
+ <id>with-java8-tests</id>
+ <properties>
+ <maven.compiler.source>1.8</maven.compiler.source>
+ <maven.compiler.target>1.8</maven.compiler.target>
+ </properties>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <version>1.10</version>
+ <executions>
+ <execution>
+ <id>add-java8-test-source</id>
+ <phase>generate-test-sources</phase>
+ <goals>
+ <goal>add-test-source</goal>
+ </goals>
+ <configuration>
+ <sources>
+ <source>${basedir}/src/test/java8/</source>
+ </sources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ <profile>
+ <id>release</id>
+ <activation>
+ <property>
+ <name>performRelease</name>
+ <value>true</value>
+ </property>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-gpg-plugin</artifactId>
+ <version>1.6</version>
+ <executions>
+ <execution>
+ <id>sign-artifacts</id>
+ <phase>verify</phase>
+ <goals>
+ <goal>sign</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ <profile>
+ <id>findbugs</id>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>findbugs-maven-plugin</artifactId>
+ <version>3.0.3</version>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-pmd-plugin</artifactId>
+ <version>3.6</version>
+ </plugin>
+ </plugins>
+ </build>
+ <reporting>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jxr-plugin</artifactId>
+ <version>2.5</version>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>findbugs-maven-plugin</artifactId>
+ <version>3.0.3</version>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-pmd-plugin</artifactId>
+ <version>3.6</version>
+ <configuration>
+ <linkXref>true</linkXref>
+ <sourceEncoding>utf-8</sourceEncoding>
+ <minimumTokens>100</minimumTokens>
+ <targetJdk>1.5</targetJdk>
+ <excludes>
+ <exclude>**/external/*.java</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+ </plugins>
+ </reporting>
+ </profile>
+ <profile>
+ <id>android</id>
+ <properties>
+ <android.src>${project.build.directory}/android/src/</android.src>
+ <android.classes>${project.build.directory}/android/classes/</android.classes>
+ <android.test.classes>${project.build.directory}/android/test-classes/</android.test.classes>
+ </properties>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-resources-plugin</artifactId>
+ <version>2.7</version>
+ <executions>
+ <execution>
+ <id>copy-src-for-android</id>
+ <phase>generate-sources</phase>
+ <goals>
+ <goal>copy-resources</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>${android.src}</outputDirectory>
+ <resources>
+ <resource>
+ <directory>${basedir}/src/main/java</directory>
+ <filtering>false</filtering>
+ <excludes>
+ <exclude>org/yaml/snakeyaml/introspector/MethodProperty.java</exclude>
+ </excludes>
+ </resource>
+ </resources>
+ </configuration>
+ </execution>
+ <execution>
+ <id>copy-test-resources-for-android</id>
+ <phase>process-test-resources</phase>
+ <goals>
+ <goal>copy-resources</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>${android.test.classes}</outputDirectory>
+ <resources>
+ <resource>
+ <directory>${basedir}/src/test/resources</directory>
+ </resource>
+ </resources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-patch-plugin</artifactId>
+ <version>1.2</version>
+ <configuration>
+ <patchDirectory>${basedir}/src/patches/android/</patchDirectory>
+ <targetDirectory>${android.src}</targetDirectory>
+ <skipApplication>false</skipApplication>
+ <strip>4</strip>
+ </configuration>
+ <executions>
+ <execution>
+ <id>android-patches</id>
+ <phase>process-sources</phase>
+ <goals>
+ <goal>apply</goal>
+ </goals>
+ <configuration>
+ <patchTrackingFile>${project.build.directory}/android/patches-applied.txt
+ </patchTrackingFile>
+ <naturalOrderProcessing>true</naturalOrderProcessing>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-antrun-plugin</artifactId>
+ <version>1.8</version>
+ <executions>
+ <execution>
+ <id>build-for-android</id>
+ <phase>compile</phase>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ <configuration>
+ <target>
+ <mkdir dir="${android.classes}" />
+ <mkdir dir="${android.test.classes}" />
+
+ <!-- compile patched sources -->
+ <javac srcdir="${android.src}" destdir="${android.classes}" classpath="${android.classes}" encoding="${project.build.sourceEncoding}" target="1.5" source="1.5" debug="true" includeantruntime="false" fork="true" />
+
+ <!-- compile test classes. Exclude some - not for BeanAccess.FIELD -->
+ <javac srcdir="${basedir}/src/test/java:${basedir}/src/test/resources" destdir="${android.test.classes}" classpath="${android.classes}:${android.test.classes}:${junit:junit:jar}:${org.springframework:spring:jar}:${org.apache.velocity:velocity:jar}:${joda-time:joda-time:jar}" encoding="${project.build.sourceEncoding}" target="1.5" source="1.5" debug="true" includeantruntime="false" fork="true">
+ <exclude name="org/yaml/snakeyaml/introspector/MethodPropertyTest.java" />
+ <exclude name="org/yaml/snakeyaml/representer/FilterPropertyToDumpTest.java" />
+ <exclude name="org/yaml/snakeyaml/issues/issue60/CustomOrderTest.java" />
+ <exclude name="org/yaml/snakeyaml/issues/issue29/FlexibleScalarStylesInJavaBeanTest.java" />
+
+ </javac>
+ </target>
+
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>test-android</id>
+ <phase>test</phase>
+ <goals>
+ <goal>test</goal>
+ </goals>
+ <configuration>
+ <classesDirectory>${android.classes}</classesDirectory>
+ <reportsDirectory>${project.build.directory}/android/surefire-reports
+ </reportsDirectory>
+ <testClassesDirectory>${android.test.classes}</testClassesDirectory>
+ <!--
+ We ignore test failures for android build at the moment.
+ Most of the FAILs are because of testing with "property" not "field" access.
+ But we still fail whole build if there are test errors.
+ -->
+ <testFailureIgnore>true</testFailureIgnore>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <artifactId>maven-jar-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>package-android-jar</id>
+ <phase>package</phase>
+ <goals>
+ <goal>jar</goal>
+ </goals>
+ <configuration>
+ <classesDirectory>${android.classes}</classesDirectory>
+ <classifier>android</classifier>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+</project>
diff --git a/pom.yaml b/pom.yaml
new file mode 100644
index 0000000..2c2e39e
--- /dev/null
+++ b/pom.yaml
@@ -0,0 +1,360 @@
+modelVersion: 4.0.0
+groupId: org.yaml
+artifactId: snakeyaml
+version: 1.17-SNAPSHOT
+packaging: jar # TODO must be bundle
+properties: {project.scm.id: bitbucket, project.build.sourceEncoding: UTF-8}
+name: SnakeYAML
+description: YAML 1.1 parser and emitter for Java
+inceptionYear: '2008'
+url: http://www.snakeyaml.org
+issueManagement: {system: Bitbucket, url: 'https://bitbucket.org/asomov/snakeyaml/issues'}
+mailingLists:
+- {name: SnakeYAML developers and users List, post: snakeyaml-core@googlegroups.com}
+scm: {connection: 'scm:hg:http://bitbucket.org/asomov/snakeyaml', developerConnection: 'scm:hg:https://bitbucket.org/asomov/snakeyaml',
+ tag: HEAD, url: 'https://bitbucket.org/asomov/snakeyaml/src'}
+licenses:
+- {distribution: repo, name: 'Apache License, Version 2.0', url: 'http://www.apache.org/licenses/LICENSE-2.0.txt'}
+developers:
+- {email: public.somov@gmail.com, id: asomov, name: Andrey Somov}
+- {email: alexander.maslov@gmail.com, id: maslovalex, name: Alexander Maslov}
+- {email: jordanangold@gmail.com, id: Jordan, name: Jordan Angold}
+prerequisites: {maven: 3.3.1}
+dependencies:
+- {artifactId: junit, groupId: junit, optional: false, scope: test, type: jar, version: '4.12'}
+- {artifactId: spring, groupId: org.springframework, optional: false, scope: test,
+ type: jar, version: 2.5.6}
+- {artifactId: velocity, groupId: org.apache.velocity, optional: false, scope: test,
+ type: jar, version: 1.6.2}
+- {artifactId: joda-time, groupId: joda-time, optional: false, scope: test, type: jar,
+ version: '1.6'}
+distributionManagement:
+ repository: {id: sonatype-nexus-staging, layout: default, name: Nexus Release Repository,
+ uniqueVersion: true, url: 'https://oss.sonatype.org/service/local/staging/deploy/maven2/'}
+ snapshotRepository: {id: sonatype-nexus-snapshots, layout: default, name: Sonatype Nexus Snapshots,
+ uniqueVersion: false, url: 'https://oss.sonatype.org/content/repositories/snapshots/'}
+build:
+ pluginManagement:
+ plugins:
+ - {artifactId: maven-site-plugin, extensions: false, groupId: org.apache.maven.plugins,
+ inherited: true, version: '3.4'}
+ plugins:
+ - artifactId: maven-compiler-plugin
+ configuration: {source: '1.5', target: '1.5', encoding: '${project.build.sourceEncoding}'}
+ extensions: false
+ groupId: org.apache.maven.plugins
+ inherited: true
+ version: '3.3'
+ - artifactId: maven-surefire-plugin
+ configuration:
+ argLine: -Xmx512m
+ includes: {include: '**/*Test.java'}
+ excludes: {exclude: '**/ParallelTest.java'}
+ extensions: false
+ groupId: org.apache.maven.plugins
+ inherited: true
+ version: 2.18.1
+ - artifactId: maven-eclipse-plugin
+ configuration: {buildOutputDirectory: bin}
+ extensions: false
+ groupId: org.apache.maven.plugins
+ inherited: true
+ version: '2.10'
+ - artifactId: cobertura-maven-plugin
+ configuration:
+ check: {totalBranchRate: '80', totalLineRate: '95'}
+ formats: {format: xml}
+ instrumentation:
+ excludes: {exclude: org/yaml/snakeyaml/external/**}
+ executions:
+ - goals: [clean, check]
+ id: default
+ inherited: true
+ priority: 0
+ extensions: false
+ groupId: org.codehaus.mojo
+ inherited: true
+ version: '2.7'
+ - artifactId: maven-changes-plugin
+ executions:
+ - configuration: {failOnError: 'true'}
+ goals: [changes-validate]
+ id: validate-changes
+ inherited: true
+ phase: pre-site
+ priority: 0
+ extensions: false
+ groupId: org.apache.maven.plugins
+ inherited: true
+ version: '2.11'
+ - artifactId: maven-source-plugin
+ executions:
+ - goals: [jar]
+ id: default
+ inherited: true
+ priority: 0
+ extensions: false
+ groupId: org.apache.maven.plugins
+ inherited: true
+ version: '2.4'
+ - artifactId: maven-javadoc-plugin
+ configuration:
+ links: {link: 'http://java.sun.com/javase/6/docs/api/'}
+ executions:
+ - goals: [jar]
+ id: attach-javadocs
+ inherited: true
+ priority: 0
+ extensions: false
+ groupId: org.apache.maven.plugins
+ inherited: true
+ version: 2.10.3
+ - artifactId: maven-license-plugin
+ configuration:
+ header: src/etc/header.txt
+ quiet: 'false'
+ failIfMissing: 'true'
+ aggregate: 'false'
+ includes: {include: src/**/*.java}
+ excludes: {exclude: src/main/java/org/yaml/snakeyaml/external/**}
+ useDefaultExcludes: 'true'
+ useDefaultMapping: 'true'
+ strictCheck: 'true'
+ encoding: UTF-8
+ executions:
+ - goals: [format]
+ id: default
+ inherited: true
+ phase: site
+ priority: 0
+ extensions: false
+ groupId: com.mycila.maven-license-plugin
+ inherited: true
+ version: 1.10.b1
+ - artifactId: maven-bundle-plugin
+ configuration:
+ instructions: {_nouses: 'true', Export-Package: "!org.yaml.snakeyaml.external*,\n\
+ \ org.yaml.snakeyaml.*;version=${project.version}",
+ Bundle-RequiredExecutionEnvironment: J2SE-1.5}
+ extensions: true
+ groupId: org.apache.felix
+ inherited: true
+ version: 2.5.4
+ - artifactId: maven-site-plugin
+ executions:
+ - goals: [attach-descriptor]
+ id: attach-descriptor
+ inherited: true
+ priority: 0
+ extensions: false
+ groupId: org.apache.maven.plugins
+ inherited: true
+ version: '3.4'
+profiles:
+- activation: {activeByDefault: false, jdk: '[1.8,)'}
+ build:
+ plugins:
+ - artifactId: maven-javadoc-plugin
+ configuration: {additionalparam: '-Xdoclint:none'}
+ extensions: false
+ groupId: org.apache.maven.plugins
+ inherited: true
+ - artifactId: maven-site-plugin
+ configuration:
+ reportPlugins:
+ plugin:
+ groupId: org.apache.maven.plugins
+ artifactId: maven-javadoc-plugin
+ configuration: {additionalparam: '-Xdoclint:none'}
+ extensions: false
+ groupId: org.apache.maven.plugins
+ inherited: true
+ id: jdk8
+ source: pom
+- build:
+ plugins:
+ - artifactId: maven-compiler-plugin
+ configuration: {source: '1.8', target: '1.8'}
+ extensions: false
+ groupId: org.apache.maven.plugins
+ inherited: true
+ - artifactId: build-helper-maven-plugin
+ executions:
+ - configuration:
+ sources: {source: '${basedir}/src/test/java8/'}
+ goals: [add-test-source]
+ id: add-java8-test-source
+ inherited: true
+ phase: generate-test-sources
+ priority: 0
+ extensions: false
+ groupId: org.codehaus.mojo
+ inherited: true
+ version: '1.10'
+ id: with-java8-tests
+ source: pom
+- activation:
+ activeByDefault: false
+ property: {name: performRelease, value: 'true'}
+ build:
+ plugins:
+ - artifactId: maven-gpg-plugin
+ executions:
+ - goals: [sign]
+ id: sign-artifacts
+ inherited: true
+ phase: verify
+ priority: 0
+ extensions: false
+ groupId: org.apache.maven.plugins
+ inherited: true
+ version: '1.6'
+ id: release
+ source: pom
+- build:
+ plugins:
+ - {artifactId: findbugs-maven-plugin, extensions: false, groupId: org.codehaus.mojo,
+ inherited: true, version: 3.0.2}
+ - {artifactId: maven-pmd-plugin, extensions: false, groupId: org.apache.maven.plugins,
+ inherited: true, version: '3.5'}
+ id: findbugs
+ reporting:
+ excludeDefaults: false
+ plugins:
+ - {artifactId: maven-jxr-plugin, groupId: org.apache.maven.plugins, inherited: true,
+ version: '2.5'}
+ - {artifactId: findbugs-maven-plugin, groupId: org.codehaus.mojo, inherited: true,
+ version: 3.0.0}
+ - artifactId: maven-pmd-plugin
+ configuration:
+ linkXref: 'true'
+ sourceEncoding: utf-8
+ minimumTokens: '100'
+ targetJdk: '1.5'
+ excludes: {exclude: '**/external/*.java'}
+ groupId: org.apache.maven.plugins
+ inherited: true
+ version: '3.4'
+ source: pom
+- build:
+ plugins:
+ - artifactId: maven-resources-plugin
+ executions:
+ - configuration:
+ outputDirectory: ${android.src}
+ resources:
+ resource:
+ directory: ${basedir}/src/main/java
+ filtering: 'false'
+ excludes: {exclude: org/yaml/snakeyaml/introspector/MethodProperty.java}
+ goals: [copy-resources]
+ id: copy-src-for-android
+ inherited: true
+ phase: generate-sources
+ priority: 0
+ - configuration:
+ outputDirectory: ${android.test.classes}
+ resources:
+ resource: {directory: '${basedir}/src/test/resources'}
+ goals: [copy-resources]
+ id: copy-test-resources-for-android
+ inherited: true
+ phase: process-test-resources
+ priority: 0
+ extensions: false
+ groupId: org.apache.maven.plugins
+ inherited: true
+ version: '2.7'
+ - artifactId: maven-patch-plugin
+ configuration: {patchDirectory: '${basedir}/src/patches/android/', targetDirectory: '${android.src}',
+ skipApplication: 'false', strip: '4'}
+ executions:
+ - configuration: {patchTrackingFile: '${project.build.directory}/android/patches-applied.txt',
+ naturalOrderProcessing: 'true'}
+ goals: [apply]
+ id: android-patches
+ inherited: true
+ phase: process-sources
+ priority: 0
+ extensions: false
+ groupId: org.apache.maven.plugins
+ inherited: true
+ version: '1.2'
+ - artifactId: maven-antrun-plugin
+ executions:
+ - configuration:
+ target:
+ javac: {}
+ goals: [run]
+ id: build-for-android
+ inherited: true
+ phase: compile
+ priority: 0
+ extensions: false
+ groupId: org.apache.maven.plugins
+ inherited: true
+ version: '1.8'
+ - artifactId: maven-surefire-plugin
+ executions:
+ - configuration: {classesDirectory: '${android.classes}', reportsDirectory: '${project.build.directory}/android/surefire-reports',
+ testClassesDirectory: '${android.test.classes}', testFailureIgnore: 'true'}
+ goals: [test]
+ id: test-android
+ inherited: true
+ phase: test
+ priority: 0
+ extensions: false
+ groupId: org.apache.maven.plugins
+ inherited: true
+ - artifactId: maven-jar-plugin
+ executions:
+ - configuration: {classesDirectory: '${android.classes}', classifier: android}
+ goals: [jar]
+ id: package-android-jar
+ inherited: true
+ phase: package
+ priority: 0
+ extensions: false
+ groupId: org.apache.maven.plugins
+ inherited: true
+ id: android
+ properties: {android.test.classes: '${project.build.directory}/android/test-classes/',
+ android.classes: '${project.build.directory}/android/classes/', android.src: '${project.build.directory}/android/src/'}
+ source: pom
+reporting:
+ excludeDefaults: false
+ plugins:
+ - artifactId: maven-changes-plugin
+ configuration: {issueLinkTemplate: 'https://bitbucket.org/asomov/snakeyaml/issues/%ISSUE%'}
+ groupId: org.apache.maven.plugins
+ inherited: true
+ reportSets:
+ - id: default
+ inherited: true
+ reports: [changes-report]
+ version: '2.11'
+ - artifactId: maven-surefire-report-plugin
+ configuration: {showSuccess: 'true'}
+ groupId: org.apache.maven.plugins
+ inherited: true
+ version: 2.18.1
+ - artifactId: cobertura-maven-plugin
+ configuration:
+ formats: {format: xml}
+ groupId: org.codehaus.mojo
+ inherited: true
+ version: '2.6'
+ - artifactId: maven-javadoc-plugin
+ groupId: org.apache.maven.plugins
+ inherited: true
+ reportSets:
+ - configuration: {doctitle: 'API for ${project.name} ${project.version}', windowtitle: 'API
+ for ${project.name} ${project.version}', testDoctitle: 'Test API for ${project.name}
+ ${project.version}', testWindowtitle: 'Test API for ${project.name} ${project.version}'}
+ id: html
+ inherited: true
+ reports: [javadoc]
+ version: 2.10.1
+
+
+
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
new file mode 100644
index 0000000..a927430
--- /dev/null
+++ b/src/changes/changes.xml
@@ -0,0 +1,964 @@
+<document xmlns="http://maven.apache.org/changes/1.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/changes/1.0.0 http://maven.apache.org/plugins/maven-changes-plugin/xsd/changes-1.0.0.xsd">
+ <properties>
+ <title>YAML 1.1 parser and emitter</title>
+ <author email="public.somov@gmail.com">Andrey Somov</author>
+ </properties>
+ <body>
+ <release version="1.18-SNAPSHOT" date="in Mercurial" description="Maintenance">
+ <action dev="asomov" type="update" issue="332">
+ Add example for issue 332 (2016-02-24)
+ </action>
+ <action dev="asomov" type="update">
+ Build SnakeYAML for different JDKs with docker without building images (2016-02-22)
+ </action>
+ <action dev="asomov" type="update">
+ Update plugin versions (2016-02-19)
+ </action>
+ </release>
+ <release version="1.17" date="2016-02-19" description="Maintenance">
+ <action dev="maslovalex" type="fix" issue="318" due-to="Rog Sigal">
+ Use Thread.currentThread.getContextClassLoader in Class.forName instead of default one (2016-02-15)
+ </action>
+ <action dev="asomov" type="update" issue="329">
+ Add parameters to POM to change distribution server (2016-02-03)
+ </action>
+ <action dev="asomov" type="update" issue="326">
+ Relax some of the modifiers to make integration easier (2016-02-02)
+ </action>
+ <action dev="maslovalex" type="update" issue="310">
+ Make use of private/protected constructors for Scalars and 'immutable' objects.
+ Added 'src/test/java8' for Java8 specific tests (requires -Pwith-java8-tests) (2016-01-07)
+ </action>
+ <action dev="asomov" type="update" issue="320">
+ Better support to customise BaseConstructor. Make 'composer' field and constructDocument()
+ method protected (2015-10-03)
+ </action>
+ <action dev="asomov" type="fix" issue="306">
+ Better UUID support (2015-09-23)
+ </action>
+ <action dev="asomov" type="add">
+ Use Polyglot Maven: add support for YAML POM (2015-09-10)
+ </action>
+ <action dev="asomov" type="fix" issue="314">
+ Provide ability to customize anchor names (2015-08-25)
+ </action>
+ </release>
+ <release version="1.16" date="2015-08-18" description="Maintenance">
+ <action dev="asomov" type="fix" issue="308">
+ Provide Docker image for testing under different Java 8 (2015-06-19)
+ </action>
+ <action dev="asomov" type="fix" issue="302">
+ Convert binary byte[] to String when it matches the JavaBean property (2015-05-26)
+ </action>
+ <action dev="asomov" type="update">
+ The source code migrated to Bitbucket. Old commits (older then 6 years) have
+ been removed. (2015-05-20)
+ </action>
+ <action dev="asomov" type="fix" issue="212">
+ Fix a typo in an error message in ScannerImpl (2015-05-19)
+ </action>
+ <action dev="asomov" type="fix" issue="209">
+ Do not print special characters in the error message (2015-04-16)
+ </action>
+ <action dev="asomov" type="fix" issue="199">
+ Evaluate implementations for duplicate mapping keys.
+ </action>
+ </release>
+ <release version="1.15" date="2015-02-19" description="Maintenance">
+ <action dev="asomov" type="update">
+ Apply FindBugs and PMD recommendations (2015-02-16)
+ </action>
+ <action dev="asomov" type="update">
+ Added split lines option to DumperOptions to allow line splitting to be disabled. (2015-02-08)
+ </action>
+ <action dev="asomov" type="update">
+ Use Maven 3 and update plugin versions (2015-02-05)
+ </action>
+ <action dev="asomov" type="update" issue="205">
+ Add test to clarify iOS emoji character in the surrogate range (2015-02-03)
+ </action>
+ <action dev="asomov" type="fix" issue="201">
+ Fix grammar error in exception message (2014-11-18)
+ </action>
+ </release>
+ <release version="1.14" date="2014-08-29" description="Maintenance">
+ <action dev="maslovalex" type="fix" issue="197">
+ Load JavaBean with fields using custom constructors (2014-08-18)
+ </action>
+ <action dev="asomov" type="fix" issue="192">
+ Drop support for "Value Key Language-Independent Type" and '=' a standard character (2014-05-22)
+ </action>
+ <action dev="maslovalex" type="fix" issue="191">
+ Improve error message for invalid YAML document (2014-05-21)
+ </action>
+ <action dev="asomov" type="fix" issue="188">
+ Improve error message for invalid YAML document (2014-03-26)
+ </action>
+ <action dev="asomov" type="fix" issue="183">
+ Support Number class (2013-11-07)
+ </action>
+ <action dev="asomov" type="fix" issue="182">
+ Double.POSITIVE_INFINITY applied to float fields (2013-11-07)
+ </action>
+ </release>
+ <release version="1.13" date="2013-08-29" description="Maintenance">
+ <action dev="asomov" type="fix" issue="178">
+ OSGi: Specify version for exported packages (2013-06-27)
+ </action>
+ <action dev="asomov" type="fix" issue="177">
+ Improve error report while parsing a JavaBean (2013-05-14)
+ </action>
+ <action dev="Jordan" type="fix" issue="135">
+ Arrays of primitives are now fully supported (2013-04-16)
+ </action>
+ <action dev="asomov" type="fix" issue="174">
+ Duplicate anchors in an input document should not be an error (2013-04-03)
+ </action>
+ <action dev="asomov" type="fix" issue="172">
+ Using a locale with minimum number fraction digits breaks anchor generation (2013-03-30)
+ </action>
+ <action dev="asomov" type="fix" issue="171">
+ Use more generic generics in BaseRepresenter (2013-03-30)
+ </action>
+ </release>
+ <release version="1.12" date="2013-03-02" description="Maintenance">
+ <action dev="asomov" type="update">
+ The build is using JDK 1.6 (2013-03-02)
+ </action>
+ <action dev="asomov" type="fix" issue="169">
+ Make Constructor.typeDefinitions protected to be more flexible (2013-02-18)
+ </action>
+ <action dev="asomov" type="remove">
+ Remove file AUTHORS because it does not reflect the actual situation (2012-11-09)
+ </action>
+ <action dev="asomov" type="update">
+ Improve the error message when a TAB character starts a token (2012-11-06)
+ </action>
+ </release>
+ <release version="1.11" date="2012-09-29" description="Maintenance">
+ <action dev="asomov" type="fix" issue="158">
+ Fix issue 158: improve support for 32-bit characters (UTF-16 surrogate pairs) (2012-09-29)
+ </action>
+ <action dev="asomov" type="fix" issue="146">
+ Fix issue 146: empty tags should not force explicit document start (2012-09-29)
+ </action>
+ <action dev="asomov" type="fix" issue="156">
+ Fix issue 156: setSkipMissingProperties fails for non-scalar values (2012-09-05)
+ </action>
+ <action dev="asomov" type="fix" issue="155">
+ Fix issue 155: SnakeYAML must always eat its own food - a YAML document created by itself must
+ be read without exceptions (2012-09-04)
+ </action>
+ <action dev="asomov" type="update" issue="154">
+ Fix issue 154: Add option to skip missing properties when deserializing YAML into Java object (2012-07-25)
+ </action>
+ <action dev="asomov" type="update">
+ Add a test for issue 150 (2012-06-17)
+ </action>
+ <action dev="asomov" type="update">
+ Add a test for issue 151 (2012-06-14)
+ </action>
+ <action dev="asomov" type="fix">
+ Fix issue 149: Directives are no longer lost between documents (2012-06-10)
+ </action>
+ <action dev="asomov" type="update">
+ Refactor: use Version enum instead of Array of Integers.
+ This is done to simplify fixing issue 149 (2012-06-09)
+ </action>
+ <action dev="asomov" type="fix">
+ Add tests for issue 148 (2012-06-07)
+ </action>
+ <action dev="asomov" type="fix">
+ Fix issue 147: Serialized representation of character U+FFFD causes exception on deserialization (2012-06-05)
+ </action>
+ <action dev="asomov" type="fix">
+ Fix issue 145: exception.getMessage() must show the line number as exception.toString() does (2012-04-03)
+ </action>
+ <action dev="maslovalex" type="fix">
+ Fix issue 144: improve type inference for Compact Object Notation (2012-03-16)
+ </action>
+ <action dev="maslovalex" type="add">
+ Improve Android support
+ </action>
+ </release>
+ <release version="1.10" date="2012-02-08" description="Maintenance">
+ <action dev="asomov" type="update">
+ Fix issue 141: TimeZone is configurable in DumperOptions (2012-02-03)
+ </action>
+ <action dev="asomov" type="update">
+ Refactor with PMD: minor non-functional improvements (2012-01-28)
+ </action>
+ <action dev="asomov" type="update">
+ Refactor with PMD: Avoid unused method parameter 'index' in
+ Serializer and Emitter (2012-01-28)
+ </action>
+ <action dev="asomov" type="update">
+ Refactor with PMD: Composer - Avoid unused method parameter 'index' in
+ 'Composer.composeNode(Node parent, Object index)''. It was used
+ in PyYAML for kind of XPath for YAML, but it was not imported from PyYAML (2012-01-28)
+ </action>
+ <action dev="asomov" type="update">
+ Refactor Emitter: the SPACE mutable static field could be changed by malicious code or by accident.
+ Boxed value is unboxed and then immediately reboxed (2012-01-28)
+ </action>
+ <action dev="asomov" type="remove">
+ Refactor with FindBugs: remove unused ScalarAnalysis.allowDoubleQuoted (2012-01-28)
+ </action>
+ <action dev="asomov" type="update">
+ Refactor with FindBugs: do not rely on default encoding (2012-01-28)
+ </action>
+ <action dev="asomov" type="update">
+ Refactor: apply FindBugs recommendations (2012-01-28)
+ </action>
+ <action dev="maslovalex" type="fix">
+ Fix issue 139: merge should use last key in map (2012-01-24)
+ </action>
+ <action dev="asomov" type="fix">
+ Fix issue 136: tabs are allowed in plain scalars. This is a deviation from PyYAML (2012-01-11)
+ </action>
+ <action dev="asomov" type="add" issue="138">
+ Expose internal data of ReaderException (2012-01-06)
+ </action>
+ <action dev="asomov" type="fix" issue="137">
+ Respect supplementary characters (2012-01-06)
+ </action>
+ <action dev="asomov" type="add">
+ Use http://mercurial.selenic.com/wiki/EolExtension to force LF as line separator
+ for all operating systems (2011-12-20)
+ </action>
+ <action dev="asomov" type="add">
+ Add a test for issue 136 (2011-12-14)
+ </action>
+ <action dev="asomov" type="remove">
+ Deprecate the DumperOptions.calculateScalarStyle() method because it was introduced as a quick
+ fix for issue 29. Now it should not be required at all (because of the fix for issue 66),
+ or it should be implemented in the Representer (in RepresentString) (2011-10-10)
+ </action>
+ <action dev="asomov" type="fix">
+ Fix issue 66: literal scalar style is used by default for multiline scalars (2011-10-10)
+ </action>
+ <action dev="asomov" type="add">
+ An example added: how to dump multiline literal scalars (2011-10-04)
+ </action>
+ <action dev="asomov" type="add">
+ An example added: how to dump recursive object for issue 133 (2011-09-14)
+ </action>
+ <action dev="asomov" type="add">
+ A test added for issue 132 (2011-09-13)
+ </action>
+ <action dev="asomov" type="update">
+ Finish 1.9 release (2011-08-15)
+ </action>
+ </release>
+ <release version="1.9" date="2011-08-15" description="Introduce Yaml.loadAs() and Yaml.dumpAs() methods">
+ <action dev="asomov" type="update">
+ Add a test to prove that SnakeYAML is not affected by the problem reported for libyaml
+ at http://pyyaml.org/ticket/196 (2011-07-28)
+ </action>
+ <action dev="asomov" type="fix" issue="128">
+ Since timestamp contains ':' characters it is dumped with single quoted scalar style
+ in the flow context. The single quoted scalar style causes to dump the explicit tag.
+ In the block context the plain scalar can be used and the tag is not required. It may cause
+ unpredictable behaviour if the tag is required. See the comments in JodaTimeExampleTest (2011-07-25)
+ </action>
+ <action dev="asomov" type="fix" issue="130">
+ Fix scientific notation inconsistency in the YAML 1.1 specification:
+ scalar '8e-06' should be parsed as a Double (2011-07-24)
+ </action>
+ <action dev="asomov" type="remove" issue="127">
+ Do not allow to override BaseRepresenter.representData(Object data) because
+ users should instead implement Represent interface (2011-07-21)
+ </action>
+ <action dev="asomov" type="remove" issue="124">
+ Deprecate DumperOptions.explicitRoot (2011-07-20)
+ </action>
+ <action dev="asomov" type="add" issue="124">
+ Add Yaml.dumpAs(Object, Tag.MAP, FlowStyle) and Yaml.dumpAsMap(Object) methods. JavaBeanDumper is marked as deprecated (2011-07-16)
+ </action>
+ <action dev="asomov" type="add" issue="127">
+ Add example to show how to dump a custom class (2011-07-12)
+ </action>
+ <action dev="asomov" type="add" issue="129">
+ Add Yaml.serialize(Node) low level method to the public API (2011-07-14)
+ </action>
+ <action dev="asomov" type="add" issue="129">
+ Add Yaml.represent(Object) low level method to the public API (2011-07-14)
+ </action>
+ <action dev="asomov" type="add" issue="125">
+ Add support for Maven 3 via 'm3' profile (2011-07-10)
+ </action>
+ <action dev="asomov" type="remove" issue="124">
+ Remove deprecated JavaBeanParser (2011-07-05)
+ </action>
+ <action dev="asomov" type="remove" issue="124">
+ Remove redundant JavaBeanDumper.classTags set (2011-07-03)
+ </action>
+ <action dev="asomov" type="add" issue="124">
+ Add Yaml.loadAs() methods. JavaBeanLoader is marked as deprecated (2011-07-03)
+ </action>
+ <action dev="asomov" type="remove" issue="124">
+ Remove TypeDescription.root property to prepare issue 124. This is a minor backwards incompatible change.
+ Now instead of setting as root, the TypeDescription must be passed to the Contructor's constructor
+ to be taken as the root definition (2011-07-03)
+ </action>
+ <action dev="asomov" type="fix" issue="121" due-to="Jaromir">
+ Fix: close files in tests to avoid a possible file handle limit (2011-06-09)
+ </action>
+ <action dev="asomov" type="fix" issue="116" due-to="Jim Peterson">
+ Fix: Improved support for empty JavaBeans (2011-06-09)
+ </action>
+ <action dev="asomov" type="fix" issue="112" due-to="Lethargish">
+ Fix: Improved support for parameterised types in collections (2011-05-25)
+ </action>
+ <action dev="asomov" type="fix" issue="115" due-to="elkniwt">
+ Fix: parameterised JavaBeans fail to load and dump because they are treated as Maps (2011-05-16)
+ </action>
+ <action dev="asomov" type="fix" issue="114" due-to="gileadis">
+ Fix: Do not remove root tags of JavaBeans when it is not explicitly requested (2011-04-20)
+ </action>
+ <action dev="asomov" type="fix" issue="111" due-to="JordanAngold">
+ Fix: Long escaped tag URI sequences throw BufferOverflowException (2011-03-03)
+ </action>
+ <action dev="asomov" type="fix" issue="110" due-to="dmitry.s.mamonov">
+ Fix: introduce a package for external libraries and move there the 64Coder
+ and the Google's URL encoder (2011-02-24)
+ </action>
+ <action dev="asomov" type="fix" issue="109" due-to="cjalmeida">
+ Fix: ancient years must be dumped with leading zeros (2011-02-19)
+ </action>
+ <action dev="asomov" type="remove" due-to="JordanAngold">
+ Remove unused code in Constructor: Modifier.isAbstract() is not needed any more (2011-02-18)
+ </action>
+ <action dev="JordanAngold" type="fix" issue="108">
+ Enum's name property shall be dumped instead of the 'toString()' output (2011-02-16)
+ </action>
+ </release>
+ <release version="1.8" date="2011-02-15" description="Performance improvement">
+ <action dev="asomov" type="add">
+ Add example to howto Wiki:
+ How_to_substitute_object_in_YAML_document_with_a_custom_object (2011-01-27)
+ </action>
+ <action dev="asomov" type="update">
+ When the YAML document to be loaded is provided as String parse it directly
+ without making a Reader first (2011-01-23)
+ </action>
+ <action dev="asomov" type="fix" issue="106">
+ Immutable data structures in StreamReader allow to share the same buffer for all
+ the Mark instances. It makes 'withMarkContext' setting redundant (2011-01-19)
+ </action>
+ <action dev="maslovalex" type="update" issue="100">
+ Merge JavaBean properties when an explicit tag is provided (2011-01-11)
+ </action>
+ <action dev="asomov" type="update" issue="99">
+ Add an example for escaping line breaks in binary content (2011-01-03)
+ </action>
+ <action dev="asomov" type="update" issue="97">
+ Propose a solution for JavaBeans to support SortedSet property when it is encoded
+ as a sequence (2010-11-24)
+ </action>
+ <action dev="asomov" type="update" issue="59">
+ Simplify the way how the order of JavaBean properties is specified. Introduce
+ PropertyUtils.createPropertySet() method to be overridden when a specific order
+ is expected (2010-11-23)
+ </action>
+ <action dev="maslovalex" type="fix" issue="95">
+ Fix: Loading of generic collections with Array parameter(s). (2010-11-16)
+ </action>
+ <action dev="asomov" type="update" issue="94">
+ Add ChangeRuntimeClassTest as an example how to change a class for a global tag (2010-11-05)
+ </action>
+ <action dev="asomov" type="update">
+ Inner objects in Constructor become protected to be more flexible when Constructor
+ is expended (2010-10-03)
+ </action>
+ <action dev="asomov" type="update" issue="91">
+ Apply www.snakeyaml.org domain name (2010-09-20)
+ </action>
+ <action dev="asomov" type="fix" issue="90">
+ Move Base64Coder into another package to keep a separate copyright statement.
+ Base64Coder is left unchanged (2010-09-19)
+ </action>
+ <action dev="asomov" type="fix" issue="69">
+ Iterable should not be serialised as sequence (2010-09-16)
+ </action>
+ <action dev="asomov" type="update">
+ Introduce 'fast' Maven profile to quickly build cobertura reports (2010-09-16)
+ </action>
+ <action dev="asomov" type="update" issue="89">
+ Fix: Specify plugin versions in POM (2010-09-15)
+ </action>
+ <action dev="maslovalex" type="fix" issue="88">
+ Fix: Custom tag erased when referenced from generic collection (2010-09-15)
+ </action>
+ <action dev="asomov" type="update">
+ Minor refactoring in Emitter to improve performance: save calls to Constant.has() (2010-09-13)
+ </action>
+ <action dev="maslovalex" type="update">
+ Minor refactorings in Emitter to improve performance: create less Strings [r9185e0b3] (2010-09-10)
+ </action>
+ <action dev="asomov" type="update" issue="79">
+ Introduce LoaderOptions to be able to specify configuration while loading (2010-09-03)
+ </action>
+ <action dev="asomov" type="fix" issue="81">
+ Representer.representJavaBeanProperty() is given the wrong tag. Instead of the property tag,
+ the tag for the JavaBean itself is provided. (2010-09-01)
+ </action>
+ <action dev="asomov" type="update">
+ Rename JvmDetector into GenericsBugDetector (2010-08-31)
+ </action>
+ <action dev="asomov" type="fix" issue="80" due-to="SebastienRainville">
+ Fix: Timestamp is not parsed properly when milliseconds start with 0 (2010-08-24)
+ </action>
+ <action dev="maslovalex" type="update" issue="79">
+ Context for error reporting consumes a lot of resources (2010-08-21)
+ </action>
+ <action dev="asomov" type="remove">
+ Cleanup unused code in deprecated Loader and Dumper (2010-08-13)
+ </action>
+ </release>
+ <release version="1.7" date="2010-08-12" description="Simplify public API (drop Loader and Dumper)">
+ <action dev="asomov" type="update">
+ Eclipse does not run JUnit 4 tests when they are launched for the whole project (2010-08-11)
+ </action>
+ <action dev="maslovalex" type="update" issue="55">
+ Share PropertyUtils if not explicitly set in Constructor or Representer
+ (BeanAccess.FIELD works properly when JavaBean is identified by a root tag) (2010-08-11)
+ </action>
+ <action dev="asomov" type="update">
+ Create 1.7 Release Candidate 1 (2010-08-11)
+ </action>
+ <action dev="asomov" type="update" issue="77">
+ Simplify public API: Drop Dumper (2010-08-06)
+ </action>
+ <action dev="asomov" type="update" issue="77">
+ Simplify public API: Drop Loader (2010-08-05)
+ </action>
+ <action dev="asomov" type="update" issue="75" due-to="jon.p.hermes">
+ Add examples to create scalars that match custom regular expression:
+ CustomImplicitResolverTest, CustomBeanResolverTest (2010-08-03)
+ </action>
+ <action dev="asomov" type="fix" issue="74" due-to="Kevin Menard">
+ Do not use redundant tags for arrays which are JavaBean properties. (2010-07-21)
+ </action>
+ <action dev="asomov" type="update">
+ RecursiveSetTest proves that it is possible to construct a recursive set (2010-07-20)
+ </action>
+ <action dev="asomov" type="add" issue="73" due-to="birnbuazn">
+ Provide sequence support for loading java.util.Set. Also provide an example
+ to serialise a java.util.Set as a sequence. (2010-07-19)
+ </action>
+ <action dev="asomov" type="add" issue="72" due-to="birnbuazn">
+ Support java.util.Collection as a parent for List and Set (2010-07-09)
+ </action>
+ <action dev="maslovalex" type="add" issue="55" due-to="birnbuazn">
+ Allow direct field access bypassing setters and getters. Empty constructor
+ is required to support 2-step construction (2010-07-02)
+ </action>
+ <action dev="asomov" type="update" issue="69">
+ Serialise Iterator and Iterable as sequences (2010-06-25)
+ </action>
+ <action dev="asomov" type="update" due-to="maslovalex">
+ Change error message when 'No suitable constructor with N arguments found for class' (2010-06-23)
+ </action>
+ <action dev="asomov" type="add" due-to="Antony Stubbs">
+ Add JodaTime example (2010-06-04)
+ </action>
+ <action dev="asomov" type="add" issue="67" due-to="Manuel Sugawara">
+ Add possibility to create a Tag out of an URI (2010-05-31)
+ </action>
+ <action dev="asomov" type="update">
+ URLDecoder.decode() does not fail when UTF-8 is invalid. Use
+ CodingErrorAction.REPORT to implement the failure (2010-05-21)
+ </action>
+ <action dev="maslovalex" type="update">
+ Fix generic collections which contain other collections (2010-05-18)
+ </action>
+ <action dev="asomov" type="fix" issue="67" due-to="Manuel Sugawara">
+ Fix: java classes containing non-ASCII characters in names are
+ incorrectly encoded (2010-05-14)
+ </action>
+ <action dev="asomov" type="fix" issue="65" due-to="lerch.johannes">
+ Fix: add checks for null arguments for JavaBeanDumper (2010-04-27)
+ </action>
+ <action dev="asomov" type="add">
+ Add a test to see how stack trace is serialised (2010-04-27)
+ </action>
+ <action dev="asomov" type="fix" issue="64" due-to="maxim.moschko">
+ ClassCastException in Representer when working with ParameterizedType (2010-04-25)
+ </action>
+ <action dev="asomov" type="update">
+ Improve toString() method for Node. Since scalars cannot be recursive
+ they can be printed (2010-04-15)
+ </action>
+ <action dev="maslovalex" type="fix" issue="63" due-to="Udo">
+ Refactor the way arrays are constructed (2010-04-15)
+ </action>
+ <action dev="asomov" type="fix" issue="62">
+ Add examples for dumping custom values for !!bool and !!null (2010-04-13)
+ </action>
+ <action dev="asomov" type="fix" issue="61">
+ Fix: ClassCastException when dumping generic bean (2010-04-11)
+ </action>
+ <action dev="asomov" type="fix" issue="59">
+ Provide an example for changing JavaBean properties order (2010-04-01)
+ </action>
+ <action dev="asomov" type="fix" issue="60">
+ Provide example for skipping null and empty collections (2010-03-29)
+ </action>
+ <action dev="asomov" type="fix" issue="58" due-to="jeff.caulfield">
+ JavaBeanDumper.dump throws NullPointerException on list property
+ with null element (2010-03-23)
+ </action>
+ <action dev="asomov" type="fix" issue="56" due-to="DZeiss">
+ Make constructors in SafeConstructor public (2010-03-16)
+ </action>
+ <action dev="asomov" type="update" due-to="David Bernard">
+ Releases and snapshots are available in the Sonatype Maven repository.
+ https://docs.sonatype.org/display/Repository/Sonatype+OSS+Maven+Repository+Usage+Guide
+ </action>
+ <action dev="obastard" type="fix" issue="53" due-to="obastard">
+ Enhancement for a pretty format that combines BLOCK and FLOW (2010-03-03)
+ </action>
+ <action dev="asomov" type="fix" issue="50" due-to="sualeh.fatehi">
+ Unable to dump JavaBean that inherits from a protected base class (2010-03-02)
+ </action>
+ <action dev="asomov" type="update">
+ Format source (2010-03-01)
+ </action>
+ <action dev="asomov" type="update">
+ Use Token.ID and Event.ID instead of just ID (2010-03-01)
+ </action>
+ <action dev="asomov" type="update">
+ Issue 50 fails in Eclipse but works with Maven (2010-03-01)
+ </action>
+ </release>
+ <release version="1.6" date="2010-02-26" description="introduce Tag class">
+ <action dev="asomov" type="update">
+ Release Candidate 2 is available (2010-02-24)
+ </action>
+ <action dev="asomov" type="fix" issue="47" due-to="obastard">
+ Don't dump read-only properties by default. DumperOptions gets a setting to
+ include read-only JavaBean properties.
+ This is no backwards compatible change (2010-02-19)
+ </action>
+ <action dev="asomov" type="fix" issue="49" due-to="obastard">
+ Support GregorianCalendar. Due to Daylight Saving Time parsing the timestamp with
+ a TimeZone cannot determine the exact time (2010-02-19)
+ </action>
+ <action dev="asomov" type="fix" issue="51" due-to="johann.Werner">
+ Some Unicode characters are wrongly replaced by \x{fffd} during
+ double quoted style dump (2010-02-15)
+ </action>
+ <action dev="asomov" type="fix" issue="48" due-to="obastard">
+ Introduce representJavaBeanProperty() method in Representer. The method
+ can be overridden to simplify custom JavaBean representation (2010-02-12)
+ </action>
+ <action dev="asomov" type="update">
+ Release Candidate 1 is available (2010-02-01)
+ </action>
+ <action dev="asomov" type="add">
+ Representer.representJavaBean() returns MappingNode (2010-01-26)
+ </action>
+ <action dev="asomov" type="add">
+ Add example of serialising static fields (2010-01-26)
+ </action>
+ <action dev="asomov" type="add">
+ Add example of serialising java.io.File as scalar node for issue 46 (2010-01-25)
+ </action>
+ <action dev="asomov" type="update">
+ Refactor: introduce Chomping to avoid using null as value for Boolean.
+ Stay in line with Scala port where null is not allowed (2010-01-19)
+ </action>
+ <action dev="asomov" type="update">
+ Refactor: use Event.ID enum instead of classes (2010-01-15)
+ </action>
+ <action dev="asomov" type="update">
+ Refactor: use Token.ID enum instead of classes (2010-01-15)
+ </action>
+ <action dev="asomov" type="update">
+ Refactor: use generic classes for DirectiveToken (2010-01-14)
+ </action>
+ <action dev="asomov" type="update">
+ Refactor: rename Reader to StreamReader to avoid name conflict with java.io.Reader (2010-01-13)
+ </action>
+ <action dev="asomov" type="update">
+ Refactor: use StringBuilder instead of StringBuffer (2010-01-12)
+ </action>
+ <action dev="asomov" type="update">
+ Refactor: introduce Constant class to share String constants (2010-01-12)
+ </action>
+ <action dev="asomov" type="update">
+ Keep Tag.equals(String) to simplify transition to Tag class (2010-01-08)
+ </action>
+ <action dev="asomov" type="update">
+ Refactor: introduce Tag instead of Tags. Nodes use Tag class instead of String (2010-01-05)
+ </action>
+ <action dev="asomov" type="fix" issue="42" due-to="Artem">
+ BaseConstructor shall give more flexibility to choose a constructor at runtime (2010-01-08)
+ </action>
+ <action dev="asomov" type="update">
+ Refactor: introduce TagTuple instead of String[] (2010-01-04)
+ </action>
+ <action dev="asomov" type="fix" issue="40" due-to="sitrious">
+ Ignore tags when they are compatible with the runtime class (2010-01-04)
+ </action>
+ <action dev="asomov" type="add">
+ Add example to ignore unknown tags (2009-12-08)
+ </action>
+ <action dev="asomov" type="add">
+ Add Ruby example (2009-12-08)
+ </action>
+ <action dev="asomov" type="update">
+ Do not omit the tag for JavaBean properties when the tag is explicitly defined (2009-12-08)
+ </action>
+ <action dev="asomov" type="fix" issue="38" due-to="gchpaco">
+ Fix ID format for numbers over 999 (2009-12-05)
+ </action>
+ <action dev="asomov" type="fix" issue="29" due-to="grignaak">
+ Allow separate option in DumperOptions for long strings (2009-11-16)
+ </action>
+ <action dev="asomov" type="add">
+ JavaBeanDumper: add possibility to define a custom Representer (2009-11-25)
+ </action>
+ <action dev="asomov" type="fix" issue="36">
+ Introduce multi contructors (tag prefix). A family of tags may be processed
+ by a single constructor (2009-11-25)
+ </action>
+ <action dev="asomov" type="update">
+ Refactor BaseConstructor: simplify second step for recursive structures (2009-11-25)
+ </action>
+ <action dev="asomov" type="add">
+ Add FilterPropertyToDumpTest to show how to filter JavaBean properties (2009-11-24)
+ </action>
+ <action dev="asomov" type="add">
+ Add FilterClassesConstructorTest to show how to filter created classes (2009-11-16)
+ </action>
+ <action dev="asomov" type="update" due-to="Stefan">
+ Improve JavaDoc (2009-11-12)
+ </action>
+ <action dev="asomov" type="add">
+ Add Velocity example (2009-11-03)
+ </action>
+ <action dev="asomov" type="update">
+ Refactor: rename Tuple to RecursiveTuple and hide it inside BaseConstructor (2009-11-03)
+ </action>
+ </release>
+ <release version="1.5" date="2009-10-30" description="Improve usage of generic collections in JavaBeans">
+ <action dev="asomov" type="fix" issue="27" due-to="Polyglot Maven team">
+ Extend Resolver to support custom implicit types (2009-10-27)
+ </action>
+ <action dev="asomov" type="update">
+ Performance improvement: use ArrayStack instead of Stack which extends Vector (2009-10-20)
+ </action>
+ <action dev="asomov" type="fix" issue="25" due-to="Benjamin Bentmann">
+ Improve usage of generic collections: while type erase makes no difference between
+ Class< Foo> and Class< Bar> at runtime, the information about generics is still
+ accessible via reflection from Method/Field. (2009-10-19)
+ </action>
+ <action dev="asomov" type="update">
+ Fix ConstructYamlObject: support recursive objects. Introduce 'resolved'
+ property for Nodes. This property supposed to help to distinguish explicit tag
+ from the resolved tag (2009-10-19)
+ </action>
+ <action dev="asomov" type="update">
+ Refactor: use rootTag instead of rootType (for Class) in BaseConstructor. This is done to
+ solve the priority problem: normally explicit tag has more priority then runtime class but
+ for the root tag it is the other way around (2009-10-19)
+ </action>
+ <action dev="asomov" type="fix" issue="24" due-to="shrode">
+ Line numbers reported in Exceptions are Zero based, should be 1 based (2009-10-12)
+ </action>
+ <action dev="asomov" type="fix" issue="21" due-to="ashwin.jayaprakash">
+ Support arrays of reference types as JavaBean properties (2009-09-22)
+ </action>
+ <action dev="asomov" type="fix" issue="17" due-to="jcucurull">
+ Respect root tag for sequences (2009-09-04)
+ </action>
+ <action dev="asomov" type="fix" issue="18" due-to="creiniger">
+ SafeRepresenter respects custom tags for standard Java classes where standard tag has
+ more then one Java implementation available (Long, List, Map, Date etc) (2009-09-03)
+ </action>
+ <action dev="asomov" type="add">
+ Add possibility to define a custom Class Loader. (2009-09-01)
+ </action>
+ <action dev="asomov" type="fix">
+ Fixed an obscure scanner error not reported when there is no line break at the end
+ of the stream. The fix is imported from PyYAML 3.09 {ticket 118} (2009-08-31)
+ </action>
+ <action dev="asomov" type="fix" issue="16" due-to="infinity0x">
+ Cache JavaBean class properties. Tests show that the loading has become a few percents faster (2009-08-31)
+ </action>
+ <action dev="asomov" type="add">
+ Introduce ArrayStack to use push() and pop() instead of standard (and too verbose)
+ 'remove(size()-1)' (2009-08-27)
+ </action>
+ <action dev="asomov" type="fix" issue="14" due-to="infinity0x">
+ Fix: ArrayList is more efficient than LinkedList (2009-08-26)
+ </action>
+ </release>
+ <release version="1.4" date="2009-08-26" description="better support for loading immutable objects">
+ <action dev="asomov" type="update">
+ Apply Apache License Version 2.0 (2009-08-14)
+ </action>
+ <action dev="asomov" type="fix" issue="13" due-to="infinity0x">
+ Provide javadocs link to Sun Java API (2009-08-10)
+ </action>
+ <action dev="asomov" type="add">
+ Build 1.4 Release Candidate 1 (2009-08-07)
+ </action>
+ <action dev="asomov" type="add">
+ Introduce Tags.getGlobalTagForClass() to simplify tag generation in custom constructors (2009-08-06)
+ </action>
+ <action dev="asomov" type="update">
+ Refactor: introduce ImplicitTuple (2009-08-06)
+ </action>
+ <action dev="asomov" type="fix" issue="11" due-to="infinity0x">
+ Fix: create a Java instance with the following priority to choose the class:
+ Explicit tag -> Runtime class (defined in JavaBean) -> implicit tag (2009-08-06)
+ </action>
+ <action dev="asomov" type="fix" issue="9" due-to="wwagner4">
+ Fix: Bean with no property cannot be instantiated. This is implemented via better
+ support for immutable objects. Custom Constructor may be used when there are more
+ then 1 way to create an instance (2009-08-04)
+ </action>
+ <action dev="asomov" type="add">
+ Deliver possibility to load immutable instances with no global tags. Reflection for
+ constructor arguments is used to get the runtime classes (2009-08-04)
+ </action>
+ <action dev="asomov" type="update">
+ Use more informative error message when a JavaBean property cannot
+ be created (2009-08-02)
+ </action>
+ <action dev="asomov" type="update">
+ Refactor: Constructor is rewritten. Do not overwrite methods from BaseConstructor.
+ Instead introduce ConstructScalar, ConstructSequence, ConstructMapping (2009-07-31)
+ </action>
+ <action dev="asomov" type="update">
+ Change Maven repository path: groupId='org.yaml', artifactId='snakeyaml' (2009-07-31)
+ </action>
+ <action dev="asomov" type="fix" issue="10" due-to="derrick.rice">
+ Fix: dump omits JavaBean class name when used with an alias (2009-07-28)
+ </action>
+ <action dev="asomov" type="add">
+ Generate sources and Javadoc (2009-07-27)
+ </action>
+ <action dev="asomov" type="update">
+ Node does not have the value. It is delegated to the non-abstract classes (2009-07-27)
+ </action>
+ <action dev="asomov" type="add">
+ Extends JavaBeanDumper to allow skipping global tags inside type-safe collections.
+ Introduce method setMapTagForBean() (2009-07-22)
+ </action>
+ <action dev="asomov" type="add">
+ Add ConstructEmptyBeanTest to test JavaBean construction with no
+ properties in the YAML document(2009-07-22)
+ </action>
+ <action dev="asomov" type="remove">
+ Refactor: redesign tag management for JavaBeans in Representer.
+ Drop dynamic root tag concept (2009-07-22)
+ </action>
+ <action dev="asomov" type="remove">
+ Remove unused TypeDescription in Representer (2009-07-21)
+ </action>
+ <action dev="asomov" type="update">
+ Use NodeTuple instead of Node[] for mappings (2009-07-21)
+ </action>
+ <action dev="asomov" type="add">
+ Introduce JavaBeanLoader and JavaBeanDumper. Deprecate JavaBeanParser (2009-07-21)
+ </action>
+ <action dev="asomov" type="fix" issue="8" due-to="Alan Gutierrez">
+ Fix: Representer was keeping state between invocations (2009-07-21)
+ </action>
+ </release>
+ <release version="1.3" date="2009-07-20" description="complete support for recursive objects">
+ <action dev="asomov" type="fix" issue="6" due-to="infinity0x">
+ Fix: values returned by System.identityHashCode() are not guaranteed to be unique (2009-07-14)
+ </action>
+ <action dev="asomov" type="add">
+ Add a simple test for Java Generics (BirdTest). Unfortunately it shows that some JVM
+ implementations do not recognise classes for JavaBean properties at runtime.
+ It leads to unnecessary global tags. See http://code.google.com/p/snakeyaml/wiki/Documentation#Generics
+ for details (2009-07-13)
+ </action>
+ <action dev="asomov" type="fix" issue="5" due-to="infinity0x">
+ Fix: set the "cause" field for MarkedYAMLException (2009-07-10)
+ </action>
+ <action dev="maslovalex" type="fix" issue="1">
+ Fix: Recursive objects are now fully supported (2009-07-09)
+ </action>
+ <action dev="asomov" type="add">
+ Add support for BigDecimal as a JavaBean property (2009-07-07)
+ </action>
+ <action dev="asomov" type="update">
+ Improve test coverage for Constructor. Allow construction of JavaBeans
+ with only setter without the corresponding getter (2009-07-07)
+ </action>
+ <action dev="asomov" type="add">
+ Add a test to check the proper report for IOException (2009-07-03)
+ </action>
+ <action dev="asomov" type="fix" issue="3" due-to="infinity0x">
+ Fix: represent proper tags for JavaBeans when they are not the root of the YAML
+ document but a member of a collection (2009-07-03)
+ </action>
+ <action dev="asomov" type="update">
+ Refactor: run PMD and apply some of the recommendations (2009-06-18)
+ </action>
+ <action dev="asomov" type="add" issue="1">
+ Create an issue for Recursive objects to be remembered (2009-06-08)
+ </action>
+ <action dev="asomov" type="update">
+ Migrate project hosting from Assembla to Google code (2009-06-08)
+ </action>
+ <action dev="asomov" type="fix" due-to="Magne">
+ Fix: null as a JavaBean property was not handled properly (2009-06-04)
+ </action>
+ <action dev="asomov" type="update">
+ Validate changes.xml file (2009-05-25)
+ </action>
+ <action dev="asomov" type="fix" due-to="Magne">
+ Fix ticket 40 in Assembla: getting an error when javabean contains java.sql.Timestamp fields (2009-05-25)
+ </action>
+ </release>
+ <release version="1.2" date="2009-04-27" description="expose low-level API">
+ <action dev="asomov" type="add">
+ Add 'Yaml.parse()' method which return Events to support low level YAML processing (2009-04-20)
+ </action>
+ <action dev="asomov" type="add" due-to="Bob Jalex">
+ Introduce LineBreak.getPlatformLineBreak (ticket 5 in Assembla) (2009-04-18)
+ </action>
+ <action dev="asomov" type="update" due-to="Bob Jalex">
+ Rename LineBreak.LINUX to LineBreak.UNIX (ticket 5 in Assembla) (2009-04-18)
+ </action>
+ <action dev="asomov" type="add">
+ Add 'Yaml.compose()' methods which return Nodes to support YEdit (2009-04-17)
+ </action>
+ <action dev="asomov" type="update">
+ Refactor: rename enums in DumperOptions to make the names consistent (2009-04-07)
+ </action>
+ <action dev="asomov" type="update">
+ Refactor: use Character instead of char primitive for style in Emitter (2009-04-07)
+ </action>
+ <action dev="asomov" type="add">
+ Add possibility to parse all scalars as Strings (2009-03-30)
+ </action>
+ <action dev="asomov" type="update">
+ Merge changeset 347 from PyYAML (2009-03-30)
+ </action>
+ <action dev="asomov" type="fix">
+ Respect DumperOptions with a custom Representer (2009-03-18)
+ </action>
+ <action dev="asomov" type="fix">
+ Represent TAB as '\t' instead of '(9' in the error message (2009-03-17)
+ </action>
+ </release>
+ <release version="1.1" date="2009-03-14" description="improve performance and test coverage">
+ <action dev="asomov" type="add">
+ Introduce JavaBeanParser (2009-03-14)
+ </action>
+ <action dev="asomov" type="add">
+ Introduce DumperOptions.Version enum (2009-03-13)
+ </action>
+ <action dev="asomov" type="add">
+ Introduce DumperOptions.LineBreak enum (2009-03-10)
+ </action>
+ <action dev="asomov" type="update">
+ Use byte[] for binary type. (2009-03-09)
+ </action>
+ <action dev="asomov" 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="asomov" 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="asomov" 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="asomov" type="add">
+ Add possibility to set a meaningful name for Yaml instance to be shown in toString(). (2009-03-05)
+ </action>
+ <action dev="asomov" type="update">
+ Refactor: declare classes which are not expected to be extended as final. (2009-03-04)
+ </action>
+ <action dev="asomov" type="update">
+ Refactor: use 'final' keyword to identify immutable fields. (2009-03-04)
+ </action>
+ <action dev="asomov" type="update">
+ Refactor: do not use 'final' keyword for local variables. (2009-03-04)
+ </action>
+ <action dev="asomov" type="fix">
+ Fix: respect implicit resolvers with 'null' as a first character. (2009-03-02)
+ </action>
+ <action dev="asomov" type="update">
+ Refactor: use Character instead of String as a key for implicit resolvers. (2009-03-02)
+ </action>
+ <action dev="asomov" type="add">
+ Use Ragel instead of Regular Expressions for implicit types. (2009-03-02)
+ </action>
+ <action dev="asomov" type="fix" due-to="Christophe Desguez">
+ Fix ticket #4 (in Assembla): java.sql.Date not handled. (2009-02-28)
+ </action>
+ <action dev="asomov" type="add">
+ Introduce DumperOptions.DefaultFlowStyle enum (2009-02-24)
+ </action>
+ <action dev="asomov" type="add">
+ Introduce DumperOptions.DefaultScalarStyle enum (2009-02-24)
+ </action>
+ <action dev="asomov" type="update">
+ Refactor: use 'switch' with Enum instead of multiple 'if' statements to distinguish nodes (2009-02-19)
+ </action>
+ <action dev="asomov" 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="asomov" type="fix">
+ Do not emit anchors for Enum (2009-02-18)
+ </action>
+ <action dev="asomov" 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="asomov" type="fix">
+ Enum is emitted as a scalar node (2009-02-17)
+ </action>
+ <action dev="asomov" type="fix" due-to="James Nissel">
+ Enum is parsed as a scalar node or as a JavaBean property (2009-02-17)
+ </action>
+ <action dev="asomov" type="update">
+ Refactor: for performance ScannerImpl.stalePossibleSimpleKeys() does not copy key Set (2009-02-10)
+ </action>
+ <action dev="asomov" type="update">
+ By default allowUnicode=true. If it is necessary to escape Unicode use
+ DumperOptions.setAllowUnicode(false) (2009-02-09)
+ </action>
+ <action dev="asomov" type="add">
+ Implement allowUnicode setting (to escape Unicode characters on non UTF-8 terminals) (2009-02-09)
+ </action>
+ <action dev="asomov" type="add">
+ Add possibility to specify tags for dumping (2009-02-09)
+ </action>
+ <action dev="asomov" type="update">
+ Rename getExpRoot to getExplicitRoot to conform with
+ standard JavaBean naming convention (2009-02-09)
+ </action>
+ <action dev="asomov" type="update">
+ Rename explictStart and explicitEnd to standard setters to conform with
+ standard JavaBean naming convention (2009-02-09)
+ </action>
+ <action dev="asomov" 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="asomov" type="add">
+ Deliver first release (2009-02-06)
+ </action>
+ </release>
+ </body>
+</document>
diff --git a/src/etc/Eclipse-format.xml b/src/etc/Eclipse-format.xml
new file mode 100644
index 0000000..4dcc5a8
--- /dev/null
+++ b/src/etc/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>
\ No newline at end of file
diff --git a/src/etc/announcement.msg b/src/etc/announcement.msg
new file mode 100644
index 0000000..a1cd13f
--- /dev/null
+++ b/src/etc/announcement.msg
@@ -0,0 +1,39 @@
+From: Andrey Somov <public.somov@gmail.com>
+To: yaml-core@lists.sourceforge.net
+Subject: [ANN] SnakeYAML-1.17 final is available
+
+==========================
+ Announcing SnakeYAML-1.17
+==========================
+
+A new release of SnakeYAML is now available:
+
+ http://www.snakeyaml.org
+
+This release delivers minor changes and bug fixes.
+
+The complete list of changes is here: https://bitbucket.org/asomov/snakeyaml/wiki/Changes
+
+Resources
+==========
+
+SnakeYAML homepage: http://www.snakeyaml.org
+SnakeYAML documentation: https://bitbucket.org/asomov/snakeyaml/wiki/Home
+
+JAR package: http://repo2.maven.org/maven2/org/yaml/snakeyaml/1.17/snakeyaml-1.17.jar
+
+YAML homepage: http://yaml.org/
+YAML-core mailing list: http://lists.sourceforge.net/lists/listinfo/yaml-core
+
+About SnakeYAML
+================
+
+SnakeYAML is a YAML parser and emitter for Java 6.
+
+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 released under the Apache License Version 2.0
diff --git a/src/etc/header.txt b/src/etc/header.txt
new file mode 100644
index 0000000..8db00b5
--- /dev/null
+++ b/src/etc/header.txt
@@ -0,0 +1,13 @@
+Copyright (c) 2008, http://www.snakeyaml.org
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
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 0000000..0762198
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/DumperOptions.java
@@ -0,0 +1,405 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml;
+
+import java.util.Map;
+import java.util.TimeZone;
+
+import org.yaml.snakeyaml.emitter.Emitter;
+import org.yaml.snakeyaml.error.YAMLException;
+import org.yaml.snakeyaml.serializer.AnchorGenerator;
+import org.yaml.snakeyaml.serializer.NumberAnchorGenerator;
+
+public class DumperOptions {
+ /**
+ * YAML provides a rich set of scalar styles. Block scalar styles include
+ * the literal style and the folded style; flow scalar styles include the
+ * plain style and two quoted styles, the single-quoted style and the
+ * double-quoted style. These styles offer a range of trade-offs between
+ * expressive power and readability.
+ *
+ * @see <a href="http://yaml.org/spec/1.1/#id903915">Chapter 9. Scalar
+ * Styles</a>
+ * @see <a href="http://yaml.org/spec/1.1/#id858081">2.3. Scalars</a>
+ */
+ public enum ScalarStyle {
+ DOUBLE_QUOTED(Character.valueOf('"')), SINGLE_QUOTED(Character.valueOf('\'')), LITERAL(
+ Character.valueOf('|')), FOLDED(Character.valueOf('>')), PLAIN(null);
+ private Character styleChar;
+
+ private ScalarStyle(Character style) {
+ this.styleChar = style;
+ }
+
+ public Character getChar() {
+ return styleChar;
+ }
+
+ @Override
+ public String toString() {
+ return "Scalar style: '" + styleChar + "'";
+ }
+
+ public static ScalarStyle createStyle(Character style) {
+ if (style == null) {
+ return PLAIN;
+ } else {
+ switch (style) {
+ case '"':
+ return DOUBLE_QUOTED;
+ case '\'':
+ return SINGLE_QUOTED;
+ case '|':
+ return LITERAL;
+ case '>':
+ return FOLDED;
+ default:
+ throw new YAMLException("Unknown scalar style character: " + style);
+ }
+ }
+ }
+ }
+
+ /**
+ * Block styles use indentation to denote nesting and scope within the
+ * document. In contrast, flow styles rely on explicit indicators to denote
+ * nesting and scope.
+ *
+ * @see <a href="http://www.yaml.org/spec/current.html#id2509255">3.2.3.1.
+ * Node Styles (http://yaml.org/spec/1.1)</a>
+ */
+ public enum FlowStyle {
+ FLOW(Boolean.TRUE), BLOCK(Boolean.FALSE), AUTO(null);
+
+ private Boolean styleBoolean;
+
+ private FlowStyle(Boolean flowStyle) {
+ styleBoolean = flowStyle;
+ }
+
+ public Boolean getStyleBoolean() {
+ return styleBoolean;
+ }
+
+ @Override
+ public String toString() {
+ return "Flow style: '" + styleBoolean + "'";
+ }
+ }
+
+ /**
+ * Platform dependent line break.
+ */
+ public enum LineBreak {
+ WIN("\r\n"), MAC("\r"), UNIX("\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 static LineBreak getPlatformLineBreak() {
+ String platformLineBreak = System.getProperty("line.separator");
+ for (LineBreak lb : values()) {
+ if (lb.lineBreak.equals(platformLineBreak)) {
+ return lb;
+ }
+ }
+ return LineBreak.UNIX;
+ }
+ }
+
+ /**
+ * Specification version. Currently supported 1.0 and 1.1
+ */
+ 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 int major() { return version[0]; }
+ public int minor() { return version[1]; }
+
+ public String getRepresentation() {
+ return version[0] + "." + version[1];
+ }
+
+ @Override
+ public String toString() {
+ return "Version: " + getRepresentation();
+ }
+ }
+
+ private ScalarStyle defaultStyle = ScalarStyle.PLAIN;
+ private FlowStyle defaultFlowStyle = FlowStyle.AUTO;
+ private boolean canonical = false;
+ private boolean allowUnicode = true;
+ private boolean allowReadOnlyProperties = false;
+ private int indent = 2;
+ private int indicatorIndent = 0;
+ private int bestWidth = 80;
+ private boolean splitLines = true;
+ private LineBreak lineBreak = LineBreak.UNIX;
+ private boolean explicitStart = false;
+ private boolean explicitEnd = false;
+ private TimeZone timeZone = null;
+
+ private Version version = null;
+ private Map<String, String> tags = null;
+ private Boolean prettyFlow = false;
+ private AnchorGenerator anchorGenerator = new NumberAnchorGenerator(0);
+
+ public boolean isAllowUnicode() {
+ return allowUnicode;
+ }
+
+ /**
+ * Specify whether to emit non-ASCII printable Unicode characters.
+ * The default value is true.
+ * When set to false then printable non-ASCII characters (Cyrillic, Chinese etc)
+ * will be not printed but escaped (to support ASCII terminals)
+ *
+ * @param allowUnicode
+ * if allowUnicode is false then all non-ASCII characters are
+ * escaped
+ */
+ public void setAllowUnicode(boolean allowUnicode) {
+ this.allowUnicode = allowUnicode;
+ }
+
+ public ScalarStyle getDefaultScalarStyle() {
+ return defaultStyle;
+ }
+
+ /**
+ * Set default style for scalars. See YAML 1.1 specification, 2.3 Scalars
+ * (http://yaml.org/spec/1.1/#id858081)
+ *
+ * @param defaultStyle
+ * set the style for all scalars
+ */
+ public void setDefaultScalarStyle(ScalarStyle defaultStyle) {
+ if (defaultStyle == null) {
+ throw new NullPointerException("Use ScalarStyle 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 setIndicatorIndent(int indicatorIndent) {
+ if (indicatorIndent < 0) {
+ throw new YAMLException("Indicator indent must be non-negative.");
+ }
+ if (indicatorIndent > Emitter.MAX_INDENT - 1) {
+ throw new YAMLException("Indicator indent must be at most Emitter.MAX_INDENT-1: " + (Emitter.MAX_INDENT - 1));
+ }
+ this.indicatorIndent = indicatorIndent;
+ }
+
+ public int getIndicatorIndent() {
+ return this.indicatorIndent;
+ }
+
+ public void setVersion(Version version) {
+ this.version = version;
+ }
+
+ public Version getVersion() {
+ return this.version;
+ }
+
+ /**
+ * Force the emitter to produce a canonical YAML document.
+ *
+ * @param canonical
+ * true produce canonical YAML document
+ */
+ public void setCanonical(boolean canonical) {
+ this.canonical = canonical;
+ }
+
+ public boolean isCanonical() {
+ return this.canonical;
+ }
+
+ /**
+ * Force the emitter to produce a pretty YAML document when using the flow
+ * style.
+ *
+ * @param prettyFlow
+ * true produce pretty flow YAML document
+ */
+ public void setPrettyFlow(boolean prettyFlow) {
+ this.prettyFlow = prettyFlow;
+ }
+
+ public boolean isPrettyFlow() {
+ return this.prettyFlow;
+ }
+
+ /**
+ * 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 width for scalars.
+ */
+ public void setWidth(int bestWidth) {
+ this.bestWidth = bestWidth;
+ }
+
+ public int getWidth() {
+ return this.bestWidth;
+ }
+
+ /**
+ * Specify whether to split lines exceeding preferred width for
+ * scalars. The default is true.
+ *
+ * @param splitLines
+ * whether to split lines exceeding preferred width for scalars.
+ */
+ public void setSplitLines(boolean splitLines) {
+ this.splitLines = splitLines;
+ }
+
+ public boolean getSplitLines() {
+ return this.splitLines;
+ }
+
+ public LineBreak getLineBreak() {
+ return lineBreak;
+ }
+
+ public void setDefaultFlowStyle(FlowStyle defaultFlowStyle) {
+ if (defaultFlowStyle == null) {
+ throw new NullPointerException("Use FlowStyle enum.");
+ }
+ this.defaultFlowStyle = defaultFlowStyle;
+ }
+
+ public FlowStyle getDefaultFlowStyle() {
+ return defaultFlowStyle;
+ }
+
+ /**
+ * Specify the line break to separate the lines. It is platform specific:
+ * Windows - "\r\n", old MacOS - "\r", Unix - "\n". The default value is the
+ * one for Unix.
+ */
+ 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;
+ }
+
+ // TODO should use Tag ???
+ public void setTags(Map<String, String> tags) {
+ this.tags = tags;
+ }
+
+ /**
+ * Report whether read-only JavaBean properties (the ones without setters)
+ * should be included in the YAML document
+ *
+ * @return false when read-only JavaBean properties are not emitted
+ */
+ public boolean isAllowReadOnlyProperties() {
+ return allowReadOnlyProperties;
+ }
+
+ /**
+ * Set to true to include read-only JavaBean properties (the ones without
+ * setters) in the YAML document. By default these properties are not
+ * included to be able to parse later the same JavaBean.
+ *
+ * @param allowReadOnlyProperties
+ * - true to dump read-only JavaBean properties
+ */
+ public void setAllowReadOnlyProperties(boolean allowReadOnlyProperties) {
+ this.allowReadOnlyProperties = allowReadOnlyProperties;
+ }
+
+ public TimeZone getTimeZone() {
+ return timeZone;
+ }
+
+ /**
+ * Set the timezone to be used for Date. If set to <code>null</code> UTC is
+ * used.
+ */
+ public void setTimeZone(TimeZone timeZone) {
+ this.timeZone = timeZone;
+ }
+
+
+ public AnchorGenerator getAnchorGenerator() {
+ return anchorGenerator;
+ }
+
+ public void setAnchorGenerator(AnchorGenerator anchorGenerator) {
+ this.anchorGenerator = anchorGenerator;
+ }
+}
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 0000000..4c38307
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/TypeDescription.java
@@ -0,0 +1,148 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.yaml.snakeyaml.nodes.Tag;
+
+/**
+ * Provides additional runtime information necessary to create a custom Java
+ * instance.
+ */
+public final class TypeDescription {
+ private final Class<? extends Object> type;
+ private Tag tag;
+ 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, Tag 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, String tag) {
+ this(clazz, new Tag(tag));
+ }
+
+ public TypeDescription(Class<? extends Object> clazz) {
+ this(clazz, (Tag) 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 Tag getTag() {
+ return tag;
+ }
+
+ /**
+ * Set tag to be used to load or dump the type (class).
+ *
+ * @param tag
+ * local or global tag
+ */
+ public void setTag(Tag tag) {
+ this.tag = tag;
+ }
+
+ public void setTag(String tag) {
+ setTag(new Tag(tag));
+ }
+
+ /**
+ * Get represented type (class)
+ *
+ * @return type (class) to be described.
+ */
+ public Class<? extends Object> getType() {
+ return type;
+ }
+
+ /**
+ * 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 0000000..5c4559c
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/Yaml.java
@@ -0,0 +1,661 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+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.DumperOptions.FlowStyle;
+import org.yaml.snakeyaml.composer.Composer;
+import org.yaml.snakeyaml.constructor.BaseConstructor;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.emitter.Emitable;
+import org.yaml.snakeyaml.emitter.Emitter;
+import org.yaml.snakeyaml.error.YAMLException;
+import org.yaml.snakeyaml.events.Event;
+import org.yaml.snakeyaml.introspector.BeanAccess;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.Tag;
+import org.yaml.snakeyaml.parser.Parser;
+import org.yaml.snakeyaml.parser.ParserImpl;
+import org.yaml.snakeyaml.reader.StreamReader;
+import org.yaml.snakeyaml.reader.UnicodeReader;
+import org.yaml.snakeyaml.representer.Representer;
+import org.yaml.snakeyaml.resolver.Resolver;
+import org.yaml.snakeyaml.serializer.Serializer;
+
+/**
+ * Public YAML interface. Each Thread must have its own instance.
+ */
+public class Yaml {
+ protected final Resolver resolver;
+ private String name;
+ protected BaseConstructor constructor;
+ protected Representer representer;
+ protected DumperOptions dumperOptions;
+
+ /**
+ * Create Yaml instance. It is safe to create a few instances and use them
+ * in different Threads.
+ */
+ public Yaml() {
+ this(new Constructor(), new Representer(), new DumperOptions(), new Resolver());
+ }
+
+ /**
+ * Create Yaml instance.
+ *
+ * @param dumperOptions
+ * DumperOptions to configure outgoing objects
+ */
+ public Yaml(DumperOptions dumperOptions) {
+ this(new Constructor(), new Representer(), dumperOptions);
+ }
+
+ /**
+ * Create Yaml instance. It is safe to create a few instances and use them
+ * in different Threads.
+ *
+ * @param representer
+ * Representer to emit outgoing objects
+ */
+ public Yaml(Representer representer) {
+ this(new Constructor(), representer);
+ }
+
+ /**
+ * Create Yaml instance. It is safe to create a few instances and use them
+ * in different Threads.
+ *
+ * @param constructor
+ * BaseConstructor to construct incoming documents
+ */
+ public Yaml(BaseConstructor constructor) {
+ this(constructor, new Representer());
+ }
+
+ /**
+ * Create Yaml instance. It is safe to create a few instances and use them
+ * in different Threads.
+ *
+ * @param constructor
+ * BaseConstructor to construct incoming documents
+ * @param representer
+ * Representer to emit outgoing objects
+ */
+ public Yaml(BaseConstructor constructor, Representer representer) {
+ this(constructor, representer, new DumperOptions());
+ }
+
+ /**
+ * Create Yaml instance. It is safe to create a few instances and use them
+ * in different Threads.
+ *
+ * @param representer
+ * Representer to emit outgoing objects
+ * @param dumperOptions
+ * DumperOptions to configure outgoing objects
+ */
+ public Yaml(Representer representer, DumperOptions dumperOptions) {
+ this(new Constructor(), representer, dumperOptions, new Resolver());
+ }
+
+ /**
+ * Create Yaml instance. It is safe to create a few instances and use them
+ * in different Threads.
+ *
+ * @param constructor
+ * BaseConstructor to construct incoming documents
+ * @param representer
+ * Representer to emit outgoing objects
+ * @param dumperOptions
+ * DumperOptions to configure outgoing objects
+ */
+ public Yaml(BaseConstructor constructor, Representer representer, DumperOptions dumperOptions) {
+ this(constructor, representer, dumperOptions, new Resolver());
+ }
+
+ /**
+ * Create Yaml instance. It is safe to create a few instances and use them
+ * in different Threads.
+ *
+ * @param constructor
+ * BaseConstructor to construct incoming documents
+ * @param representer
+ * Representer to emit outgoing objects
+ * @param dumperOptions
+ * DumperOptions to configure outgoing objects
+ * @param resolver
+ * Resolver to detect implicit type
+ */
+ public Yaml(BaseConstructor constructor, Representer representer, DumperOptions dumperOptions,
+ Resolver resolver) {
+ if (!constructor.isExplicitPropertyUtils()) {
+ constructor.setPropertyUtils(representer.getPropertyUtils());
+ } else if (!representer.isExplicitPropertyUtils()) {
+ representer.setPropertyUtils(constructor.getPropertyUtils());
+ }
+ this.constructor = constructor;
+ representer.setDefaultFlowStyle(dumperOptions.getDefaultFlowStyle());
+ representer.setDefaultScalarStyle(dumperOptions.getDefaultScalarStyle());
+ representer.getPropertyUtils().setAllowReadOnlyProperties(
+ dumperOptions.isAllowReadOnlyProperties());
+ representer.setTimeZone(dumperOptions.getTimeZone());
+ this.representer = representer;
+ this.dumperOptions = dumperOptions;
+ this.resolver = resolver;
+ this.name = "Yaml:" + System.identityHashCode(this);
+ }
+
+ /**
+ * 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> list = new ArrayList<Object>(1);
+ list.add(data);
+ return dumpAll(list.iterator());
+ }
+
+ /**
+ * Produce the corresponding representation tree for a given Object.
+ *
+ * @see <a href="http://yaml.org/spec/1.1/#id859333">Figure 3.1. Processing
+ * Overview</a>
+ * @param data
+ * instance to build the representation tree for
+ * @return representation tree
+ */
+ public Node represent(Object data) {
+ return representer.represent(data);
+ }
+
+ /**
+ * 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, null);
+ 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> list = new ArrayList<Object>(1);
+ list.add(data);
+ dumpAll(list.iterator(), output, null);
+ }
+
+ /**
+ * 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) {
+ dumpAll(data, output, null);
+ }
+
+ private void dumpAll(Iterator<? extends Object> data, Writer output, Tag rootTag) {
+ Serializer serializer = new Serializer(new Emitter(output, dumperOptions), resolver,
+ dumperOptions, rootTag);
+ try {
+ serializer.open();
+ while (data.hasNext()) {
+ Node node = representer.represent(data.next());
+ serializer.serialize(node);
+ }
+ serializer.close();
+ } catch (IOException e) {
+ throw new YAMLException(e);
+ }
+ }
+
+ /**
+ * <p>
+ * Serialize a Java object into a YAML string. Override the default root tag
+ * with <code>rootTag</code>.
+ * </p>
+ *
+ * <p>
+ * This method is similar to <code>Yaml.dump(data)</code> except that the
+ * root tag for the whole document is replaced with the given tag. This has
+ * two main uses.
+ * </p>
+ *
+ * <p>
+ * First, if the root tag is replaced with a standard YAML tag, such as
+ * <code>Tag.MAP</code>, then the object will be dumped as a map. The root
+ * tag will appear as <code>!!map</code>, or blank (implicit !!map).
+ * </p>
+ *
+ * <p>
+ * Second, if the root tag is replaced by a different custom tag, then the
+ * document appears to be a different type when loaded. For example, if an
+ * instance of MyClass is dumped with the tag !!YourClass, then it will be
+ * handled as an instance of YourClass when loaded.
+ * </p>
+ *
+ * @param data
+ * Java object to be serialized to YAML
+ * @param rootTag
+ * the tag for the whole YAML document. The tag should be Tag.MAP
+ * for a JavaBean to make the tag disappear (to use implicit tag
+ * !!map). If <code>null</code> is provided then the standard tag
+ * with the full class name is used.
+ * @param flowStyle
+ * flow style for the whole document. See Chapter 10. Collection
+ * Styles http://yaml.org/spec/1.1/#id930798. If
+ * <code>null</code> is provided then the flow style from
+ * DumperOptions is used.
+ *
+ * @return YAML String
+ */
+ public String dumpAs(Object data, Tag rootTag, FlowStyle flowStyle) {
+ FlowStyle oldStyle = representer.getDefaultFlowStyle();
+ if (flowStyle != null) {
+ representer.setDefaultFlowStyle(flowStyle);
+ }
+ List<Object> list = new ArrayList<Object>(1);
+ list.add(data);
+ StringWriter buffer = new StringWriter();
+ dumpAll(list.iterator(), buffer, rootTag);
+ representer.setDefaultFlowStyle(oldStyle);
+ return buffer.toString();
+ }
+
+ /**
+ * <p>
+ * Serialize a Java object into a YAML string. Override the default root tag
+ * with <code>Tag.MAP</code>.
+ * </p>
+ * <p>
+ * This method is similar to <code>Yaml.dump(data)</code> except that the
+ * root tag for the whole document is replaced with <code>Tag.MAP</code> tag
+ * (implicit !!map).
+ * </p>
+ * <p>
+ * Block Mapping is used as the collection style. See 10.2.2. Block Mappings
+ * (http://yaml.org/spec/1.1/#id934537)
+ * </p>
+ *
+ * @param data
+ * Java object to be serialized to YAML
+ * @return YAML String
+ */
+ public String dumpAsMap(Object data) {
+ return dumpAs(data, Tag.MAP, FlowStyle.BLOCK);
+ }
+
+ /**
+ * Serialize the representation tree into Events.
+ *
+ * @see <a href="http://yaml.org/spec/1.1/#id859333">Processing Overview</a>
+ * @param data
+ * representation tree
+ * @return Event list
+ */
+ public List<Event> serialize(Node data) {
+ SilentEmitter emitter = new SilentEmitter();
+ Serializer serializer = new Serializer(emitter, resolver, dumperOptions, null);
+ try {
+ serializer.open();
+ serializer.serialize(data);
+ serializer.close();
+ } catch (IOException e) {
+ throw new YAMLException(e);
+ }
+ return emitter.getEvents();
+ }
+
+ private static class SilentEmitter implements Emitable {
+ private List<Event> events = new ArrayList<Event>(100);
+
+ public List<Event> getEvents() {
+ return events;
+ }
+
+ public void emit(Event event) throws IOException {
+ events.add(event);
+ }
+ }
+
+ /**
+ * Parse the only 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 loadFromReader(new StreamReader(yaml), Object.class);
+ }
+
+ /**
+ * Parse the only 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 loadFromReader(new StreamReader(new UnicodeReader(io)), Object.class);
+ }
+
+ /**
+ * Parse the only 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(Reader io) {
+ return loadFromReader(new StreamReader(io), Object.class);
+ }
+
+ /**
+ * Parse the only YAML document in a stream and produce the corresponding
+ * Java object.
+ *
+ * @param <T>
+ * Class is defined by the second argument
+ * @param io
+ * data to load from (BOM must not be present)
+ * @param type
+ * Class of the object to be created
+ * @return parsed object
+ */
+ @SuppressWarnings("unchecked")
+ public <T> T loadAs(Reader io, Class<T> type) {
+ return (T) loadFromReader(new StreamReader(io), type);
+ }
+
+ /**
+ * Parse the only YAML document in a String and produce the corresponding
+ * Java object. (Because the encoding in known BOM is not respected.)
+ *
+ * @param <T>
+ * Class is defined by the second argument
+ * @param yaml
+ * YAML data to load from (BOM must not be present)
+ * @param type
+ * Class of the object to be created
+ * @return parsed object
+ */
+ @SuppressWarnings("unchecked")
+ public <T> T loadAs(String yaml, Class<T> type) {
+ return (T) loadFromReader(new StreamReader(yaml), type);
+ }
+
+ /**
+ * Parse the only YAML document in a stream and produce the corresponding
+ * Java object.
+ *
+ * @param <T>
+ * Class is defined by the second argument
+ * @param input
+ * data to load from (BOM is respected and removed)
+ * @param type
+ * Class of the object to be created
+ * @return parsed object
+ */
+ @SuppressWarnings("unchecked")
+ public <T> T loadAs(InputStream input, Class<T> type) {
+ return (T) loadFromReader(new StreamReader(new UnicodeReader(input)), type);
+ }
+
+ private Object loadFromReader(StreamReader sreader, Class<?> type) {
+ Composer composer = new Composer(new ParserImpl(sreader), resolver);
+ constructor.setComposer(composer);
+ return constructor.getSingleData(type);
+ }
+
+ /**
+ * Parse all YAML documents in a String and produce corresponding Java
+ * objects. The documents are parsed only when the iterator is invoked.
+ *
+ * @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(Reader yaml) {
+ Composer composer = new Composer(new ParserImpl(new StreamReader(yaml)), resolver);
+ 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 static class YamlIterable implements Iterable<Object> {
+ private Iterator<Object> iterator;
+
+ public YamlIterable(Iterator<Object> iterator) {
+ this.iterator = iterator;
+ }
+
+ public Iterator<Object> iterator() {
+ return iterator;
+ }
+ }
+
+ /**
+ * Parse all YAML documents in a String and produce corresponding Java
+ * objects. (Because the encoding in known BOM is not respected.) The
+ * documents are parsed only when the iterator is invoked.
+ *
+ * @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. The documents are parsed only when the iterator is invoked.
+ *
+ * @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));
+ }
+
+ /**
+ * Parse the first YAML document in a stream and produce the corresponding
+ * representation tree. (This is the opposite of the represent() method)
+ *
+ * @see <a href="http://yaml.org/spec/1.1/#id859333">Figure 3.1. Processing
+ * Overview</a>
+ * @param yaml
+ * YAML document
+ * @return parsed root Node for the specified YAML document
+ */
+ public Node compose(Reader yaml) {
+ Composer composer = new Composer(new ParserImpl(new StreamReader(yaml)), resolver);
+ constructor.setComposer(composer);
+ return composer.getSingleNode();
+ }
+
+ /**
+ * Parse all YAML documents in a stream and produce corresponding
+ * representation trees.
+ *
+ * @see <a href="http://yaml.org/spec/1.1/#id859333">Processing Overview</a>
+ * @param yaml
+ * stream of YAML documents
+ * @return parsed root Nodes for all the specified YAML documents
+ */
+ public Iterable<Node> composeAll(Reader yaml) {
+ final Composer composer = new Composer(new ParserImpl(new StreamReader(yaml)), resolver);
+ constructor.setComposer(composer);
+ Iterator<Node> result = new Iterator<Node>() {
+ public boolean hasNext() {
+ return composer.checkNode();
+ }
+
+ public Node next() {
+ return composer.getNode();
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ return new NodeIterable(result);
+ }
+
+ private static class NodeIterable implements Iterable<Node> {
+ private Iterator<Node> iterator;
+
+ public NodeIterable(Iterator<Node> iterator) {
+ this.iterator = iterator;
+ }
+
+ public Iterator<Node> iterator() {
+ return iterator;
+ }
+ }
+
+ /**
+ * Add an implicit scalar detector. If an implicit scalar value matches the
+ * given regexp, the corresponding tag is assigned to the scalar.
+ *
+ * @param tag
+ * tag to assign to the node
+ * @param regexp
+ * regular expression to match against
+ * @param first
+ * a sequence of possible initial characters or null (which means
+ * any).
+ */
+ public void addImplicitResolver(Tag tag, Pattern regexp, String first) {
+ resolver.addImplicitResolver(tag, regexp, first);
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+
+ /**
+ * Get a meaningful name. It simplifies debugging in a multi-threaded
+ * environment. If nothing is set explicitly the address of the instance is
+ * returned.
+ *
+ * @return human readable 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;
+ }
+
+ /**
+ * Parse a YAML stream and produce parsing events.
+ *
+ * @see <a href="http://yaml.org/spec/1.1/#id859333">Processing Overview</a>
+ * @param yaml
+ * YAML document(s)
+ * @return parsed events
+ */
+ public Iterable<Event> parse(Reader yaml) {
+ final Parser parser = new ParserImpl(new StreamReader(yaml));
+ Iterator<Event> result = new Iterator<Event>() {
+ public boolean hasNext() {
+ return parser.peekEvent() != null;
+ }
+
+ public Event next() {
+ return parser.getEvent();
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ return new EventIterable(result);
+ }
+
+ private static class EventIterable implements Iterable<Event> {
+ private Iterator<Event> iterator;
+
+ public EventIterable(Iterator<Event> iterator) {
+ this.iterator = iterator;
+ }
+
+ public Iterator<Event> iterator() {
+ return iterator;
+ }
+ }
+
+ public void setBeanAccess(BeanAccess beanAccess) {
+ constructor.getPropertyUtils().setBeanAccess(beanAccess);
+ representer.getPropertyUtils().setBeanAccess(beanAccess);
+ }
+
+}
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 0000000..f8223c2
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/composer/Composer.java
@@ -0,0 +1,248 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.composer;
+
+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 org.yaml.snakeyaml.events.AliasEvent;
+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.nodes.MappingNode;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.NodeId;
+import org.yaml.snakeyaml.nodes.NodeTuple;
+import org.yaml.snakeyaml.nodes.ScalarNode;
+import org.yaml.snakeyaml.nodes.SequenceNode;
+import org.yaml.snakeyaml.nodes.Tag;
+import org.yaml.snakeyaml.parser.Parser;
+import org.yaml.snakeyaml.resolver.Resolver;
+
+/**
+ * Creates a node graph from parser events.
+ * <p>
+ * Corresponds to the 'Compose' step as described in chapter 3.1 of the <a
+ * href="http://yaml.org/spec/1.1/">YAML Specification</a>.
+ * </p>
+ */
+public class Composer {
+ protected final Parser parser;
+ private final Resolver resolver;
+ private final Map<String, Node> anchors;
+ private final Set<Node> recursiveNodes;
+
+ public Composer(Parser parser, Resolver resolver) {
+ this.parser = parser;
+ this.resolver = resolver;
+ this.anchors = new HashMap<String, Node>();
+ this.recursiveNodes = new HashSet<Node>();
+ }
+
+ /**
+ * Checks if further documents are available.
+ *
+ * @return <code>true</code> if there is at least one more document.
+ */
+ public boolean checkNode() {
+ // Drop the STREAM-START event.
+ if (parser.checkEvent(Event.ID.StreamStart)) {
+ parser.getEvent();
+ }
+ // If there are more documents available?
+ return !parser.checkEvent(Event.ID.StreamEnd);
+ }
+
+ /**
+ * Reads and composes the next document.
+ *
+ * @return The root node of the document or <code>null</code> if no more
+ * documents are available.
+ */
+ public Node getNode() {
+ // Get the root node of the next document.
+ if (!parser.checkEvent(Event.ID.StreamEnd)) {
+ return composeDocument();
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Reads a document from a source that contains only one document.
+ * <p>
+ * If the stream contains more than one document an exception is thrown.
+ * </p>
+ *
+ * @return The root node of the document or <code>null</code> if no document
+ * is available.
+ */
+ 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(Event.ID.StreamEnd)) {
+ document = composeDocument();
+ }
+ // Ensure that the stream contains no more documents.
+ if (!parser.checkEvent(Event.ID.StreamEnd)) {
+ 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);
+ // Drop the DOCUMENT-END event.
+ parser.getEvent();
+ this.anchors.clear();
+ recursiveNodes.clear();
+ return node;
+ }
+
+ private Node composeNode(Node parent) {
+ recursiveNodes.add(parent);
+ if (parser.checkEvent(Event.ID.Alias)) {
+ AliasEvent event = (AliasEvent) parser.getEvent();
+ String anchor = event.getAnchor();
+ if (!anchors.containsKey(anchor)) {
+ throw new ComposerException(null, null, "found undefined alias " + anchor,
+ event.getStartMark());
+ }
+ Node result = anchors.get(anchor);
+ if (recursiveNodes.remove(result)) {
+ result.setTwoStepsConstruction(true);
+ }
+ return result;
+ }
+ NodeEvent event = (NodeEvent) parser.peekEvent();
+ String anchor = null;
+ anchor = event.getAnchor();
+ // the check for duplicate anchors has been removed (issue 174)
+ Node node = null;
+ if (parser.checkEvent(Event.ID.Scalar)) {
+ node = composeScalarNode(anchor);
+ } else if (parser.checkEvent(Event.ID.SequenceStart)) {
+ node = composeSequenceNode(anchor);
+ } else {
+ node = composeMappingNode(anchor);
+ }
+ recursiveNodes.remove(parent);
+ return node;
+ }
+
+ protected Node composeScalarNode(String anchor) {
+ ScalarEvent ev = (ScalarEvent) parser.getEvent();
+ String tag = ev.getTag();
+ boolean resolved = false;
+ Tag nodeTag;
+ if (tag == null || tag.equals("!")) {
+ nodeTag = resolver.resolve(NodeId.scalar, ev.getValue(), ev.getImplicit()
+ .canOmitTagInPlainScalar());
+ resolved = true;
+ } else {
+ nodeTag = new Tag(tag);
+ }
+ Node node = new ScalarNode(nodeTag, resolved, ev.getValue(), ev.getStartMark(),
+ ev.getEndMark(), ev.getStyle());
+ if (anchor != null) {
+ anchors.put(anchor, node);
+ }
+ return node;
+ }
+
+ protected Node composeSequenceNode(String anchor) {
+ SequenceStartEvent startEvent = (SequenceStartEvent) parser.getEvent();
+ String tag = startEvent.getTag();
+ Tag nodeTag;
+ boolean resolved = false;
+ if (tag == null || tag.equals("!")) {
+ nodeTag = resolver.resolve(NodeId.sequence, null, startEvent.getImplicit());
+ resolved = true;
+ } else {
+ nodeTag = new Tag(tag);
+ }
+ final ArrayList<Node> children = new ArrayList<Node>();
+ SequenceNode node = new SequenceNode(nodeTag, resolved, children,
+ startEvent.getStartMark(), null, startEvent.getFlowStyle());
+ if (anchor != null) {
+ anchors.put(anchor, node);
+ }
+ while (!parser.checkEvent(Event.ID.SequenceEnd)) {
+ children.add(composeNode(node));
+ }
+ Event endEvent = parser.getEvent();
+ node.setEndMark(endEvent.getEndMark());
+ return node;
+ }
+
+ protected Node composeMappingNode(String anchor) {
+ MappingStartEvent startEvent = (MappingStartEvent) parser.getEvent();
+ String tag = startEvent.getTag();
+ Tag nodeTag;
+ boolean resolved = false;
+ if (tag == null || tag.equals("!")) {
+ nodeTag = resolver.resolve(NodeId.mapping, null, startEvent.getImplicit());
+ resolved = true;
+ } else {
+ nodeTag = new Tag(tag);
+ }
+
+ final List<NodeTuple> children = new ArrayList<NodeTuple>();
+ MappingNode node = new MappingNode(nodeTag, resolved, children, startEvent.getStartMark(),
+ null, startEvent.getFlowStyle());
+ if (anchor != null) {
+ anchors.put(anchor, node);
+ }
+ while (!parser.checkEvent(Event.ID.MappingEnd)) {
+ composeMappingChildren(children, node);
+ }
+ Event endEvent = parser.getEvent();
+ node.setEndMark(endEvent.getEndMark());
+ return node;
+ }
+
+ protected void composeMappingChildren(List<NodeTuple> children, MappingNode node) {
+ Node itemKey = composeKeyNode(node);
+ if (itemKey.getTag().equals(Tag.MERGE)) {
+ node.setMerged(true);
+ }
+ Node itemValue = composeValueNode(node);
+ children.add(new NodeTuple(itemKey, itemValue));
+ }
+
+ protected Node composeKeyNode(MappingNode node) {
+ return composeNode(node);
+ }
+
+ protected Node composeValueNode(MappingNode node) {
+ return composeNode(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 0000000..5d20c1d
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/composer/ComposerException.java
@@ -0,0 +1,27 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.composer;
+
+import org.yaml.snakeyaml.error.Mark;
+import org.yaml.snakeyaml.error.MarkedYAMLException;
+
+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/AbstractConstruct.java b/src/main/java/org/yaml/snakeyaml/constructor/AbstractConstruct.java
new file mode 100644
index 0000000..61d14f6
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/constructor/AbstractConstruct.java
@@ -0,0 +1,41 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.constructor;
+
+import org.yaml.snakeyaml.error.YAMLException;
+import org.yaml.snakeyaml.nodes.Node;
+
+/**
+ * Because recursive structures are not very common we provide a way to save
+ * some typing when extending a constructor
+ */
+public abstract class AbstractConstruct implements Construct {
+
+ /**
+ * Fail with a reminder to provide the seconds step for a recursive
+ * structure
+ *
+ * @see org.yaml.snakeyaml.constructor.Construct#construct2ndStep(org.yaml.snakeyaml.nodes.Node,
+ * java.lang.Object)
+ */
+ public void construct2ndStep(Node node, Object data) {
+ if (node.isTwoStepsConstruction()) {
+ throw new IllegalStateException("Not Implemented in " + getClass().getName());
+ } else {
+ throw new YAMLException("Unexpected recursive structure for Node: " + node);
+ }
+ }
+}
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 0000000..3a504cb
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/constructor/BaseConstructor.java
@@ -0,0 +1,450 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.constructor;
+
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.EnumMap;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.yaml.snakeyaml.composer.Composer;
+import org.yaml.snakeyaml.composer.ComposerException;
+import org.yaml.snakeyaml.error.YAMLException;
+import org.yaml.snakeyaml.introspector.PropertyUtils;
+import org.yaml.snakeyaml.nodes.MappingNode;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.NodeId;
+import org.yaml.snakeyaml.nodes.NodeTuple;
+import org.yaml.snakeyaml.nodes.ScalarNode;
+import org.yaml.snakeyaml.nodes.SequenceNode;
+import org.yaml.snakeyaml.nodes.Tag;
+
+public abstract class BaseConstructor {
+ /**
+ * It maps the node kind to the the Construct implementation. When the
+ * runtime class is known then the implicit tag is ignored.
+ */
+ protected final Map<NodeId, Construct> yamlClassConstructors = new EnumMap<NodeId, Construct>(
+ NodeId.class);
+ /**
+ * It maps the (explicit or implicit) tag to the Construct implementation.
+ * It is used: <br/>
+ * 1) explicit tag - if present. <br/>
+ * 2) implicit tag - when the runtime class of the instance is unknown (the
+ * node has the Object.class)
+ */
+ protected final Map<Tag, Construct> yamlConstructors = new HashMap<Tag, Construct>();
+ /**
+ * It maps the (explicit or implicit) tag to the Construct implementation.
+ * It is used when no exact match found.
+ */
+ protected final Map<String, Construct> yamlMultiConstructors = new HashMap<String, Construct>();
+
+ protected Composer composer;
+ private final Map<Node, Object> constructedObjects;
+ private final Set<Node> recursiveObjects;
+ private final ArrayList<RecursiveTuple<Map<Object, Object>, RecursiveTuple<Object, Object>>> maps2fill;
+ private final ArrayList<RecursiveTuple<Set<Object>, Object>> sets2fill;
+
+ protected Tag rootTag;
+ private PropertyUtils propertyUtils;
+ private boolean explicitPropertyUtils;
+
+ public BaseConstructor() {
+ constructedObjects = new HashMap<Node, Object>();
+ recursiveObjects = new HashSet<Node>();
+ maps2fill = new ArrayList<RecursiveTuple<Map<Object, Object>, RecursiveTuple<Object, Object>>>();
+ sets2fill = new ArrayList<RecursiveTuple<Set<Object>, Object>>();
+ rootTag = null;
+ explicitPropertyUtils = false;
+ }
+
+ public void setComposer(Composer composer) {
+ this.composer = composer;
+ }
+
+ /**
+ * Check if more documents available
+ *
+ * @return true when there are more YAML documents in the stream
+ */
+ public boolean checkData() {
+ // If there are more documents available?
+ return composer.checkNode();
+ }
+
+ /**
+ * Construct and return the next document
+ *
+ * @return constructed instance
+ */
+ public Object getData() {
+ // Construct and return the next document.
+ composer.checkNode();
+ Node node = composer.getNode();
+ if (rootTag != null) {
+ node.setTag(rootTag);
+ }
+ return constructDocument(node);
+ }
+
+ /**
+ * Ensure that the stream contains a single document and construct it
+ *
+ * @return constructed instance
+ * @throws ComposerException
+ * in case there are more documents in the stream
+ */
+ public Object getSingleData(Class<?> type) {
+ // Ensure that the stream contains a single document and construct it
+ Node node = composer.getSingleNode();
+ if (node != null) {
+ if (Object.class != type) {
+ node.setTag(new Tag(type));
+ } else if (rootTag != null) {
+ node.setTag(rootTag);
+ }
+ return constructDocument(node);
+ }
+ return null;
+ }
+
+ /**
+ * Construct complete YAML document. Call the second step in case of
+ * recursive structures. At the end cleans all the state.
+ *
+ * @param node
+ * root Node
+ * @return Java instance
+ */
+ protected final Object constructDocument(Node node) {
+ Object data = constructObject(node);
+ fillRecursive();
+ constructedObjects.clear();
+ recursiveObjects.clear();
+ return data;
+ }
+
+ private void fillRecursive() {
+ if (!maps2fill.isEmpty()) {
+ for (RecursiveTuple<Map<Object, Object>, RecursiveTuple<Object, Object>> entry : maps2fill) {
+ RecursiveTuple<Object, Object> key_value = entry._2();
+ entry._1().put(key_value._1(), key_value._2());
+ }
+ maps2fill.clear();
+ }
+ if (!sets2fill.isEmpty()) {
+ for (RecursiveTuple<Set<Object>, Object> value : sets2fill) {
+ value._1().add(value._2());
+ }
+ sets2fill.clear();
+ }
+ }
+
+ /**
+ * Construct object from the specified Node. Return existing instance if the
+ * node is already constructed.
+ *
+ * @param node
+ * Node to be constructed
+ * @return Java instance
+ */
+ protected Object constructObject(Node node) {
+ if (constructedObjects.containsKey(node)) {
+ return constructedObjects.get(node);
+ }
+ if (recursiveObjects.contains(node)) {
+ throw new ConstructorException(null, null, "found unconstructable recursive node",
+ node.getStartMark());
+ }
+ recursiveObjects.add(node);
+ Construct constructor = getConstructor(node);
+ Object data = constructor.construct(node);
+ constructedObjects.put(node, data);
+ recursiveObjects.remove(node);
+ if (node.isTwoStepsConstruction()) {
+ constructor.construct2ndStep(node, data);
+ }
+ return data;
+ }
+
+ /**
+ * Get the constructor to construct the Node. For implicit tags if the
+ * runtime class is known a dedicated Construct implementation is used.
+ * Otherwise the constructor is chosen by the tag.
+ *
+ * @param node
+ * Node to be constructed
+ * @return Construct implementation for the specified node
+ */
+ protected Construct getConstructor(Node node) {
+ if (node.useClassConstructor()) {
+ return yamlClassConstructors.get(node.getNodeId());
+ } else {
+ Construct constructor = yamlConstructors.get(node.getTag());
+ if (constructor == null) {
+ for (String prefix : yamlMultiConstructors.keySet()) {
+ if (node.getTag().startsWith(prefix)) {
+ return yamlMultiConstructors.get(prefix);
+ }
+ }
+ return yamlConstructors.get(null);
+ }
+ return constructor;
+ }
+ }
+
+ protected Object constructScalar(ScalarNode node) {
+ return node.getValue();
+ }
+
+ protected List<Object> createDefaultList(int initSize) {
+ return new ArrayList<Object>(initSize);
+ }
+
+ protected Set<Object> createDefaultSet(int initSize) {
+ return new LinkedHashSet<Object>(initSize);
+ }
+
+ protected Object createArray(Class<?> type, int size) {
+ return Array.newInstance(type.getComponentType(), size);
+ }
+
+ @SuppressWarnings("unchecked")
+ protected List<? extends Object> constructSequence(SequenceNode node) {
+ List<Object> result;
+ if (List.class.isAssignableFrom(node.getType()) && !node.getType().isInterface()) {
+ // the root class may be defined (Vector for instance)
+ try {
+ result = (List<Object>) node.getType().newInstance();
+ } catch (Exception e) {
+ throw new YAMLException(e);
+ }
+ } else {
+ result = createDefaultList(node.getValue().size());
+ }
+ constructSequenceStep2(node, result);
+ return result;
+
+ }
+
+ @SuppressWarnings("unchecked")
+ protected Set<? extends Object> constructSet(SequenceNode node) {
+ Set<Object> result;
+ if (!node.getType().isInterface()) {
+ // the root class may be defined
+ try {
+ result = (Set<Object>) node.getType().newInstance();
+ } catch (Exception e) {
+ throw new YAMLException(e);
+ }
+ } else {
+ result = createDefaultSet(node.getValue().size());
+ }
+ constructSequenceStep2(node, result);
+ return result;
+
+ }
+
+ protected Object constructArray(SequenceNode node) {
+ return constructArrayStep2(node, createArray(node.getType(), node.getValue().size()));
+ }
+
+ protected void constructSequenceStep2(SequenceNode node, Collection<Object> collection) {
+ for (Node child : node.getValue()) {
+ collection.add(constructObject(child));
+ }
+ }
+
+ protected Object constructArrayStep2(SequenceNode node, Object array) {
+ final Class<?> componentType = node.getType().getComponentType();
+
+ int index = 0;
+ for (Node child : node.getValue()) {
+ // Handle multi-dimensional arrays...
+ if (child.getType() == Object.class) {
+ child.setType(componentType);
+ }
+
+ final Object value = constructObject(child);
+
+ if (componentType.isPrimitive()) {
+ // Null values are disallowed for primitives
+ if (value == null) {
+ throw new NullPointerException("Unable to construct element value for " + child);
+ }
+
+ // Primitive arrays require quite a lot of work.
+ if (byte.class.equals(componentType)) {
+ Array.setByte(array, index, ((Number) value).byteValue());
+
+ } else if (short.class.equals(componentType)) {
+ Array.setShort(array, index, ((Number) value).shortValue());
+
+ } else if (int.class.equals(componentType)) {
+ Array.setInt(array, index, ((Number) value).intValue());
+
+ } else if (long.class.equals(componentType)) {
+ Array.setLong(array, index, ((Number) value).longValue());
+
+ } else if (float.class.equals(componentType)) {
+ Array.setFloat(array, index, ((Number) value).floatValue());
+
+ } else if (double.class.equals(componentType)) {
+ Array.setDouble(array, index, ((Number) value).doubleValue());
+
+ } else if (char.class.equals(componentType)) {
+ Array.setChar(array, index, ((Character) value).charValue());
+
+ } else if (boolean.class.equals(componentType)) {
+ Array.setBoolean(array, index, ((Boolean) value).booleanValue());
+
+ } else {
+ throw new YAMLException("unexpected primitive type");
+ }
+
+ } else {
+ // Non-primitive arrays can simply be assigned:
+ Array.set(array, index, value);
+ }
+
+ ++index;
+ }
+ return array;
+ }
+
+ protected Map<Object, Object> createDefaultMap() {
+ // respect order from YAML document
+ return new LinkedHashMap<Object, Object>();
+ }
+
+ protected Set<Object> createDefaultSet() {
+ // respect order from YAML document
+ return new LinkedHashSet<Object>();
+ }
+
+ protected Set<Object> constructSet(MappingNode node) {
+ Set<Object> set = createDefaultSet();
+ constructSet2ndStep(node, set);
+ return set;
+ }
+
+ protected Map<Object, Object> constructMapping(MappingNode node) {
+ Map<Object, Object> mapping = createDefaultMap();
+ constructMapping2ndStep(node, mapping);
+ return mapping;
+ }
+
+ protected void constructMapping2ndStep(MappingNode node, Map<Object, Object> mapping) {
+ List<NodeTuple> nodeValue = (List<NodeTuple>) node.getValue();
+ for (NodeTuple tuple : nodeValue) {
+ Node keyNode = tuple.getKeyNode();
+ Node valueNode = tuple.getValueNode();
+ 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
+ .getKeyNode().getStartMark(), e);
+ }
+ }
+ Object value = constructObject(valueNode);
+ if (keyNode.isTwoStepsConstruction()) {
+ /*
+ * if keyObject is created it 2 steps we should postpone putting
+ * it in map because it may have different hash after
+ * initialization compared to clean just created one. And map of
+ * course does not observe key hashCode changes.
+ */
+ maps2fill.add(0,
+ new RecursiveTuple<Map<Object, Object>, RecursiveTuple<Object, Object>>(
+ mapping, new RecursiveTuple<Object, Object>(key, value)));
+ } else {
+ mapping.put(key, value);
+ }
+ }
+ }
+
+ protected void constructSet2ndStep(MappingNode node, Set<Object> set) {
+ List<NodeTuple> nodeValue = (List<NodeTuple>) node.getValue();
+ for (NodeTuple tuple : nodeValue) {
+ Node keyNode = tuple.getKeyNode();
+ Object key = constructObject(keyNode);
+ if (key != null) {
+ try {
+ key.hashCode();// check circular dependencies
+ } catch (Exception e) {
+ throw new ConstructorException("while constructing a Set", node.getStartMark(),
+ "found unacceptable key " + key, tuple.getKeyNode().getStartMark(), e);
+ }
+ }
+ if (keyNode.isTwoStepsConstruction()) {
+ /*
+ * if keyObject is created it 2 steps we should postpone putting
+ * it into the set because it may have different hash after
+ * initialization compared to clean just created one. And set of
+ * course does not observe value hashCode changes.
+ */
+ sets2fill.add(0, new RecursiveTuple<Set<Object>, Object>(set, key));
+ } else {
+ set.add(key);
+ }
+ }
+ }
+
+ public void setPropertyUtils(PropertyUtils propertyUtils) {
+ this.propertyUtils = propertyUtils;
+ explicitPropertyUtils = true;
+ }
+
+ public final PropertyUtils getPropertyUtils() {
+ if (propertyUtils == null) {
+ propertyUtils = new PropertyUtils();
+ }
+ return propertyUtils;
+ }
+
+ private static class RecursiveTuple<T, K> {
+ private final T _1;
+ private final K _2;
+
+ public RecursiveTuple(T _1, K _2) {
+ this._1 = _1;
+ this._2 = _2;
+ }
+
+ public K _2() {
+ return _2;
+ }
+
+ public T _1() {
+ return _1;
+ }
+ }
+
+ public final boolean isExplicitPropertyUtils() {
+ return explicitPropertyUtils;
+ }
+}
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 0000000..4fa9118
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/constructor/Construct.java
@@ -0,0 +1,50 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.constructor;
+
+import org.yaml.snakeyaml.nodes.Node;
+
+/**
+ * Provide a way to construct a Java instance out of the composed Node. Support
+ * recursive objects if it is required. (create Native Data Structure out of
+ * Node Graph)
+ *
+ * @see <a href="http://yaml.org/spec/1.1/#id859109">Chapter 3. Processing YAML
+ * Information</a>
+ */
+public interface Construct {
+ /**
+ * Construct a Java instance with all the properties injected when it is
+ * possible.
+ *
+ * @param node
+ * composed Node
+ * @return a complete Java instance
+ */
+ Object construct(Node node);
+
+ /**
+ * Apply the second step when constructing recursive structures. Because the
+ * instance is already created it can assign a reference to itself.
+ *
+ * @param node
+ * composed Node
+ * @param object
+ * the instance constructed earlier by
+ * <code>construct(Node node)</code> for the provided Node
+ */
+ void construct2ndStep(Node node, Object object);
+}
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 0000000..943702f
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/constructor/Constructor.java
@@ -0,0 +1,682 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.constructor;
+
+import java.beans.IntrospectionException;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.SortedSet;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.UUID;
+
+import org.yaml.snakeyaml.TypeDescription;
+import org.yaml.snakeyaml.error.YAMLException;
+import org.yaml.snakeyaml.introspector.Property;
+import org.yaml.snakeyaml.nodes.MappingNode;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.NodeId;
+import org.yaml.snakeyaml.nodes.NodeTuple;
+import org.yaml.snakeyaml.nodes.ScalarNode;
+import org.yaml.snakeyaml.nodes.SequenceNode;
+import org.yaml.snakeyaml.nodes.Tag;
+
+/**
+ * Construct a custom Java instance.
+ */
+public class Constructor extends SafeConstructor {
+ private final Map<Tag, Class<? extends Object>> typeTags;
+ protected final Map<Class<? extends Object>, TypeDescription> typeDefinitions;
+
+ public Constructor() {
+ this(Object.class);
+ }
+
+ /**
+ * Create Constructor for the specified class as the root.
+ *
+ * @param theRoot
+ * - the class (usually JavaBean) to be constructed
+ */
+ public Constructor(Class<? extends Object> theRoot) {
+ this(new TypeDescription(checkRoot(theRoot)));
+ }
+
+ /**
+ * Ugly Java way to check the argument in the constructor
+ */
+ private static Class<? extends Object> checkRoot(Class<? extends Object> theRoot) {
+ if (theRoot == null) {
+ throw new NullPointerException("Root class must be provided.");
+ } else
+ return theRoot;
+ }
+
+ public Constructor(TypeDescription theRoot) {
+ if (theRoot == null) {
+ throw new NullPointerException("Root type must be provided.");
+ }
+ this.yamlConstructors.put(null, new ConstructYamlObject());
+ if (!Object.class.equals(theRoot.getType())) {
+ rootTag = new Tag(theRoot.getType());
+ }
+ typeTags = new HashMap<Tag, Class<? extends Object>>();
+ typeDefinitions = new HashMap<Class<? extends Object>, TypeDescription>();
+ yamlClassConstructors.put(NodeId.scalar, new ConstructScalar());
+ yamlClassConstructors.put(NodeId.mapping, new ConstructMapping());
+ yamlClassConstructors.put(NodeId.sequence, new ConstructSequence());
+ addTypeDescription(theRoot);
+ }
+
+ /**
+ * 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 class (usually
+ * 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.");
+ }
+ Tag tag = definition.getTag();
+ typeTags.put(tag, definition.getType());
+ return typeDefinitions.put(definition.getType(), definition);
+ }
+
+ /**
+ * Construct mapping instance (Map, JavaBean) when the runtime class is
+ * known.
+ */
+ protected class ConstructMapping implements Construct {
+
+ /**
+ * 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
+ */
+ public Object construct(Node node) {
+ MappingNode mnode = (MappingNode) node;
+ if (Properties.class.isAssignableFrom(node.getType())) {
+ Properties properties = new Properties();
+ if (!node.isTwoStepsConstruction()) {
+ constructMapping2ndStep(mnode, properties);
+ } else {
+ throw new YAMLException("Properties must not be recursive.");
+ }
+ return properties;
+ } else if (SortedMap.class.isAssignableFrom(node.getType())) {
+ SortedMap<Object, Object> map = new TreeMap<Object, Object>();
+ if (!node.isTwoStepsConstruction()) {
+ constructMapping2ndStep(mnode, map);
+ }
+ return map;
+ } else if (Map.class.isAssignableFrom(node.getType())) {
+ if (node.isTwoStepsConstruction()) {
+ return createDefaultMap();
+ } else {
+ return constructMapping(mnode);
+ }
+ } else if (SortedSet.class.isAssignableFrom(node.getType())) {
+ SortedSet<Object> set = new TreeSet<Object>();
+ // XXX why this is not used ?
+ // if (!node.isTwoStepsConstruction()) {
+ constructSet2ndStep(mnode, set);
+ // }
+ return set;
+ } else if (Collection.class.isAssignableFrom(node.getType())) {
+ if (node.isTwoStepsConstruction()) {
+ return createDefaultSet();
+ } else {
+ return constructSet(mnode);
+ }
+ } else {
+ if (node.isTwoStepsConstruction()) {
+ return createEmptyJavaBean(mnode);
+ } else {
+ return constructJavaBean2ndStep(mnode, createEmptyJavaBean(mnode));
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public void construct2ndStep(Node node, Object object) {
+ if (Map.class.isAssignableFrom(node.getType())) {
+ constructMapping2ndStep((MappingNode) node, (Map<Object, Object>) object);
+ } else if (Set.class.isAssignableFrom(node.getType())) {
+ constructSet2ndStep((MappingNode) node, (Set<Object>) object);
+ } else {
+ constructJavaBean2ndStep((MappingNode) node, object);
+ }
+ }
+
+ protected Object createEmptyJavaBean(MappingNode node) {
+ try {
+ /**
+ * Using only default constructor. Everything else will be
+ * initialized on 2nd step. If we do here some partial
+ * initialization, how do we then track what need to be done on
+ * 2nd step? I think it is better to get only object here (to
+ * have it as reference for recursion) and do all other thing on
+ * 2nd step.
+ */
+ java.lang.reflect.Constructor<?> c = node.getType().getDeclaredConstructor();
+ c.setAccessible(true);
+ return c.newInstance();
+ } catch (Exception e) {
+ throw new YAMLException(e);
+ }
+ }
+
+ protected Object constructJavaBean2ndStep(MappingNode node, Object object) {
+ flattenMapping(node);
+ Class<? extends Object> beanType = node.getType();
+ List<NodeTuple> nodeValue = node.getValue();
+ for (NodeTuple tuple : nodeValue) {
+ ScalarNode keyNode;
+ if (tuple.getKeyNode() instanceof ScalarNode) {
+ // key must be scalar
+ keyNode = (ScalarNode) tuple.getKeyNode();
+ } else {
+ throw new YAMLException("Keys must be scalars but found: " + tuple.getKeyNode());
+ }
+ Node valueNode = tuple.getValueNode();
+ // keys can only be Strings
+ keyNode.setType(String.class);
+ String key = (String) constructObject(keyNode);
+ try {
+ Property property = getProperty(beanType, key);
+ valueNode.setType(property.getType());
+ TypeDescription memberDescription = typeDefinitions.get(beanType);
+ boolean typeDetected = false;
+ 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);
+ typeDetected = true;
+ } else if (property.getType().isArray()) {
+ snode.setListType(property.getType().getComponentType());
+ typeDetected = true;
+ }
+ break;
+ case mapping:
+ MappingNode mnode = (MappingNode) valueNode;
+ Class<? extends Object> keyType = memberDescription.getMapKeyType(key);
+ if (keyType != null) {
+ mnode.setTypes(keyType, memberDescription.getMapValueType(key));
+ typeDetected = true;
+ }
+ break;
+ default: // scalar
+ }
+ }
+ if (!typeDetected && valueNode.getNodeId() != NodeId.scalar) {
+ // only if there is no explicit TypeDescription
+ Class<?>[] arguments = property.getActualTypeArguments();
+ if (arguments != null && arguments.length > 0) {
+ // type safe (generic) collection may contain the
+ // proper class
+ if (valueNode.getNodeId() == NodeId.sequence) {
+ Class<?> t = arguments[0];
+ SequenceNode snode = (SequenceNode) valueNode;
+ snode.setListType(t);
+ } else if (valueNode.getTag().equals(Tag.SET)) {
+ Class<?> t = arguments[0];
+ MappingNode mnode = (MappingNode) valueNode;
+ mnode.setOnlyKeyType(t);
+ mnode.setUseClassConstructor(true);
+ } else if (property.getType().isAssignableFrom(Map.class)) {
+ Class<?> ketType = arguments[0];
+ Class<?> valueType = arguments[1];
+ MappingNode mnode = (MappingNode) valueNode;
+ mnode.setTypes(ketType, valueType);
+ mnode.setUseClassConstructor(true);
+ } else {
+ // the type for collection entries cannot be
+ // detected
+ }
+ }
+ }
+
+ Object value = constructObject(valueNode);
+ // Correct when the property expects float but double was
+ // constructed
+ if (property.getType() == Float.TYPE || property.getType() == Float.class) {
+ if (value instanceof Double) {
+ value = ((Double) value).floatValue();
+ }
+ }
+ // Correct when the property a String but the value is binary
+ if (property.getType() == String.class && Tag.BINARY.equals(valueNode.getTag()) && value instanceof byte[]) {
+ value = new String((byte[])value);
+ }
+
+ property.set(object, value);
+ } catch (Exception e) {
+ throw new ConstructorException("Cannot create property=" + key
+ + " for JavaBean=" + object, node.getStartMark(), e.getMessage(),
+ valueNode.getStartMark(), e);
+ }
+ }
+ return object;
+ }
+
+ protected Property getProperty(Class<? extends Object> type, String name)
+ throws IntrospectionException {
+ return getPropertyUtils().getProperty(type, name);
+ }
+ }
+
+ /**
+ * Construct an instance when the runtime class is not known but a global
+ * tag with a class name is defined. It delegates the construction to the
+ * appropriate constructor based on the node kind (scalar, sequence,
+ * mapping)
+ */
+ protected class ConstructYamlObject implements Construct {
+
+ private Construct getConstructor(Node node) {
+ Class<?> cl = getClassForNode(node);
+ node.setType(cl);
+ // call the constructor as if the runtime class is defined
+ Construct constructor = yamlClassConstructors.get(node.getNodeId());
+ return constructor;
+ }
+
+ public Object construct(Node node) {
+ Object result = null;
+ try {
+ result = getConstructor(node).construct(node);
+ } catch (ConstructorException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new ConstructorException(null, null, "Can't construct a java object for "
+ + node.getTag() + "; exception=" + e.getMessage(), node.getStartMark(), e);
+ }
+ return result;
+ }
+
+ public void construct2ndStep(Node node, Object object) {
+ try {
+ getConstructor(node).construct2ndStep(node, object);
+ } catch (Exception e) {
+ throw new ConstructorException(null, null,
+ "Can't construct a second step for a java object for " + node.getTag()
+ + "; exception=" + e.getMessage(), node.getStartMark(), e);
+ }
+ }
+ }
+
+ /**
+ * Construct scalar instance when the runtime class is known. Recursive
+ * structures are not supported.
+ */
+ protected class ConstructScalar extends AbstractConstruct {
+ public Object construct(Node nnode) {
+ ScalarNode node = (ScalarNode) nnode;
+ Class<?> type = node.getType();
+ Object result;
+ if (type.isPrimitive() || type == String.class || Number.class.isAssignableFrom(type)
+ || type == Boolean.class || Date.class.isAssignableFrom(type)
+ || type == Character.class || type == BigInteger.class
+ || type == BigDecimal.class || Enum.class.isAssignableFrom(type)
+ || Tag.BINARY.equals(node.getTag()) || Calendar.class.isAssignableFrom(type) || type == UUID.class) {
+ // standard classes created directly
+ result = constructStandardJavaInstance(type, node);
+ } else {
+ // there must be only 1 constructor with 1 argument
+ java.lang.reflect.Constructor<?>[] javaConstructors = type
+ .getDeclaredConstructors();
+ int oneArgCount = 0;
+ java.lang.reflect.Constructor<?> javaConstructor = null;
+ for (java.lang.reflect.Constructor<?> c : javaConstructors) {
+ if (c.getParameterTypes().length == 1) {
+ oneArgCount++;
+ javaConstructor = c;
+ }
+ }
+ Object argument;
+ if (javaConstructor == null) {
+ throw new YAMLException("No single argument constructor found for " + type);
+ } else if (oneArgCount == 1) {
+ argument = constructStandardJavaInstance(
+ javaConstructor.getParameterTypes()[0], node);
+ } else {
+ // TODO it should be possible to use implicit types instead
+ // of forcing String. Resolver must be available here to
+ // obtain the implicit tag. Then we can set the tag and call
+ // callConstructor(node) to create the argument instance.
+ // On the other hand it may be safer to require a custom
+ // constructor to avoid guessing the argument class
+ argument = constructScalar(node);
+ try {
+ javaConstructor = type.getDeclaredConstructor(String.class);
+ } catch (Exception e) {
+ throw new YAMLException("Can't construct a java object for scalar "
+ + node.getTag() + "; No String constructor found. Exception="
+ + e.getMessage(), e);
+ }
+ }
+ try {
+ javaConstructor.setAccessible(true);
+ result = javaConstructor.newInstance(argument);
+ } catch (Exception e) {
+ throw new ConstructorException(null, null,
+ "Can't construct a java object for scalar " + node.getTag()
+ + "; exception=" + e.getMessage(), node.getStartMark(), e);
+ }
+ }
+ return result;
+ }
+
+ @SuppressWarnings("unchecked")
+ private Object constructStandardJavaInstance(@SuppressWarnings("rawtypes")
+ Class type, ScalarNode node) {
+ Object result;
+ if (type == String.class) {
+ Construct stringConstructor = yamlConstructors.get(Tag.STR);
+ result = stringConstructor.construct(node);
+ } else if (type == Boolean.class || type == Boolean.TYPE) {
+ Construct boolConstructor = yamlConstructors.get(Tag.BOOL);
+ result = boolConstructor.construct(node);
+ } else if (type == Character.class || type == Character.TYPE) {
+ Construct charConstructor = yamlConstructors.get(Tag.STR);
+ String ch = (String) charConstructor.construct(node);
+ if (ch.length() == 0) {
+ result = null;
+ } else if (ch.length() != 1) {
+ throw new YAMLException("Invalid node Character: '" + ch + "'; length: "
+ + ch.length());
+ } else {
+ result = Character.valueOf(ch.charAt(0));
+ }
+ } else if (Date.class.isAssignableFrom(type)) {
+ Construct dateConstructor = yamlConstructors.get(Tag.TIMESTAMP);
+ Date date = (Date) dateConstructor.construct(node);
+ if (type == Date.class) {
+ result = date;
+ } else {
+ try {
+ java.lang.reflect.Constructor<?> constr = type.getConstructor(long.class);
+ result = constr.newInstance(date.getTime());
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new YAMLException("Cannot construct: '" + type + "'");
+ }
+ }
+ } else if (type == Float.class || type == Double.class || type == Float.TYPE
+ || type == Double.TYPE || type == BigDecimal.class) {
+ if (type == BigDecimal.class) {
+ result = new BigDecimal(node.getValue());
+ } else {
+ Construct doubleConstructor = yamlConstructors.get(Tag.FLOAT);
+ result = doubleConstructor.construct(node);
+ if (type == Float.class || type == Float.TYPE) {
+ result = new Float((Double) result);
+ }
+ }
+ } else if (type == Byte.class || type == Short.class || type == Integer.class
+ || type == Long.class || type == BigInteger.class || type == Byte.TYPE
+ || type == Short.TYPE || type == Integer.TYPE || type == Long.TYPE) {
+ Construct intConstructor = yamlConstructors.get(Tag.INT);
+ result = intConstructor.construct(node);
+ if (type == Byte.class || type == Byte.TYPE) {
+ result = Byte.valueOf(result.toString());
+ } else if (type == Short.class || type == Short.TYPE) {
+ result = Short.valueOf(result.toString());
+ } else if (type == Integer.class || type == Integer.TYPE) {
+ result = Integer.parseInt(result.toString());
+ } else if (type == Long.class || type == Long.TYPE) {
+ result = Long.valueOf(result.toString());
+ } else {
+ // only BigInteger left
+ result = new BigInteger(result.toString());
+ }
+ } else if (Enum.class.isAssignableFrom(type)) {
+ String enumValueName = node.getValue();
+ try {
+ result = Enum.valueOf(type, enumValueName);
+ } catch (Exception ex) {
+ throw new YAMLException("Unable to find enum value '" + enumValueName
+ + "' for enum class: " + type.getName());
+ }
+ } else if (Calendar.class.isAssignableFrom(type)) {
+ ConstructYamlTimestamp contr = new ConstructYamlTimestamp();
+ contr.construct(node);
+ result = contr.getCalendar();
+ } else if (Number.class.isAssignableFrom(type)) {
+ ConstructYamlNumber contr = new ConstructYamlNumber();
+ result = contr.construct(node);
+ } else if (UUID.class == type) {
+ result = UUID.fromString(node.getValue());
+ } else {
+ if (yamlConstructors.containsKey(node.getTag())) {
+ result = yamlConstructors.get(node.getTag()).construct(node);
+ } else {
+ throw new YAMLException("Unsupported class: " + type);
+ }
+ }
+ return result;
+ }
+ }
+
+ /**
+ * Construct sequence (List, Array, or immutable object) when the runtime
+ * class is known.
+ */
+ protected class ConstructSequence implements Construct {
+ @SuppressWarnings("unchecked")
+ public Object construct(Node node) {
+ SequenceNode snode = (SequenceNode) node;
+ if (Set.class.isAssignableFrom(node.getType())) {
+ if (node.isTwoStepsConstruction()) {
+ throw new YAMLException("Set cannot be recursive.");
+ } else {
+ return constructSet(snode);
+ }
+ } else if (Collection.class.isAssignableFrom(node.getType())) {
+ if (node.isTwoStepsConstruction()) {
+ return createDefaultList(snode.getValue().size());
+ } else {
+ return constructSequence(snode);
+ }
+ } else if (node.getType().isArray()) {
+ if (node.isTwoStepsConstruction()) {
+ return createArray(node.getType(), snode.getValue().size());
+ } else {
+ return constructArray(snode);
+ }
+ } else {
+ // create immutable object
+ List<java.lang.reflect.Constructor<?>> possibleConstructors = new ArrayList<java.lang.reflect.Constructor<?>>(
+ snode.getValue().size());
+ for (java.lang.reflect.Constructor<?> constructor : node
+ .getType().getDeclaredConstructors()) {
+ if (snode.getValue()
+ .size() == constructor.getParameterTypes().length) {
+ possibleConstructors.add(constructor);
+ }
+ }
+ if (!possibleConstructors.isEmpty()) {
+ if (possibleConstructors.size() == 1) {
+ Object[] argumentList = new Object[snode.getValue().size()];
+ java.lang.reflect.Constructor<?> c = possibleConstructors.get(0);
+ int index = 0;
+ for (Node argumentNode : snode.getValue()) {
+ Class<?> type = c.getParameterTypes()[index];
+ // set runtime classes for arguments
+ argumentNode.setType(type);
+ argumentList[index++] = constructObject(argumentNode);
+ }
+
+ try {
+ c.setAccessible(true);
+ return c.newInstance(argumentList);
+ } catch (Exception e) {
+ throw new YAMLException(e);
+ }
+ }
+
+ // use BaseConstructor
+ List<Object> argumentList = (List<Object>) constructSequence(snode);
+ Class<?>[] parameterTypes = new Class[argumentList.size()];
+ int index = 0;
+ for (Object parameter : argumentList) {
+ parameterTypes[index] = parameter.getClass();
+ index++;
+ }
+
+ for (java.lang.reflect.Constructor<?> c : possibleConstructors) {
+ Class<?>[] argTypes = c.getParameterTypes();
+ boolean foundConstructor = true;
+ for (int i = 0; i < argTypes.length; i++) {
+ if (!wrapIfPrimitive(argTypes[i]).isAssignableFrom(parameterTypes[i])) {
+ foundConstructor = false;
+ break;
+ }
+ }
+ if (foundConstructor) {
+ try {
+ c.setAccessible(true);
+ return c.newInstance(argumentList.toArray());
+ } catch (Exception e) {
+ throw new YAMLException(e);
+ }
+ }
+ }
+ }
+ throw new YAMLException("No suitable constructor with "
+ + String.valueOf(snode.getValue().size()) + " arguments found for "
+ + node.getType());
+
+ }
+ }
+
+ private final Class<? extends Object> wrapIfPrimitive(Class<?> clazz) {
+ if (!clazz.isPrimitive()) {
+ return clazz;
+ }
+ if (clazz == Integer.TYPE) {
+ return Integer.class;
+ }
+ if (clazz == Float.TYPE) {
+ return Float.class;
+ }
+ if (clazz == Double.TYPE) {
+ return Double.class;
+ }
+ if (clazz == Boolean.TYPE) {
+ return Boolean.class;
+ }
+ if (clazz == Long.TYPE) {
+ return Long.class;
+ }
+ if (clazz == Character.TYPE) {
+ return Character.class;
+ }
+ if (clazz == Short.TYPE) {
+ return Short.class;
+ }
+ if (clazz == Byte.TYPE) {
+ return Byte.class;
+ }
+ throw new YAMLException("Unexpected primitive " + clazz);
+ }
+
+ @SuppressWarnings("unchecked")
+ public void construct2ndStep(Node node, Object object) {
+ SequenceNode snode = (SequenceNode) node;
+ if (List.class.isAssignableFrom(node.getType())) {
+ List<Object> list = (List<Object>) object;
+ constructSequenceStep2(snode, list);
+ } else if (node.getType().isArray()) {
+ constructArrayStep2(snode, object);
+ } else {
+ throw new YAMLException("Immutable objects cannot be recursive.");
+ }
+ }
+ }
+
+ protected Class<?> getClassForNode(Node node) {
+ Class<? extends Object> classForTag = typeTags.get(node.getTag());
+ if (classForTag == null) {
+ String name = node.getTag().getClassName();
+ Class<?> cl;
+ try {
+ cl = getClassForName(name);
+ } catch (ClassNotFoundException e) {
+ throw new YAMLException("Class not found: " + name);
+ }
+ typeTags.put(node.getTag(), cl);
+ return cl;
+ } else {
+ return classForTag;
+ }
+ }
+
+ protected Class<?> getClassForName(String name) throws ClassNotFoundException {
+ try {
+ return Class.forName(name, true, Thread.currentThread().getContextClassLoader());
+ } catch (ClassNotFoundException e) {
+ return Class.forName(name);
+ }
+ }
+}
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 0000000..336e3ba
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/constructor/ConstructorException.java
@@ -0,0 +1,33 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.constructor;
+
+import org.yaml.snakeyaml.error.Mark;
+import org.yaml.snakeyaml.error.MarkedYAMLException;
+
+public class ConstructorException extends MarkedYAMLException {
+ private static final long serialVersionUID = -8816339931365239910L;
+
+ protected ConstructorException(String context, Mark contextMark, String problem,
+ Mark problemMark, Throwable cause) {
+ super(context, contextMark, problem, problemMark, cause);
+ }
+
+ protected ConstructorException(String context, Mark contextMark, String problem,
+ Mark problemMark) {
+ this(context, contextMark, problem, problemMark, null);
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/constructor/CustomClassLoaderConstructor.java b/src/main/java/org/yaml/snakeyaml/constructor/CustomClassLoaderConstructor.java
new file mode 100644
index 0000000..edb163d
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/constructor/CustomClassLoaderConstructor.java
@@ -0,0 +1,40 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.constructor;
+
+/**
+ * Construct instances with a custom Class Loader.
+ */
+public class CustomClassLoaderConstructor extends Constructor {
+ private ClassLoader loader = CustomClassLoaderConstructor.class.getClassLoader();
+
+ public CustomClassLoaderConstructor(ClassLoader cLoader) {
+ this(Object.class, cLoader);
+ }
+
+ public CustomClassLoaderConstructor(Class<? extends Object> theRoot, ClassLoader theLoader) {
+ super(theRoot);
+ if (theLoader == null) {
+ throw new NullPointerException("Loader must be provided.");
+ }
+ this.loader = theLoader;
+ }
+
+ @Override
+ protected Class<?> getClassForName(String name) throws ClassNotFoundException {
+ return Class.forName(name, true, loader);
+ }
+}
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 0000000..b5572ea
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/constructor/SafeConstructor.java
@@ -0,0 +1,510 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.constructor;
+
+import java.math.BigInteger;
+import java.text.NumberFormat;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TimeZone;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.yaml.snakeyaml.error.YAMLException;
+import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder;
+import org.yaml.snakeyaml.nodes.MappingNode;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.NodeId;
+import org.yaml.snakeyaml.nodes.NodeTuple;
+import org.yaml.snakeyaml.nodes.ScalarNode;
+import org.yaml.snakeyaml.nodes.SequenceNode;
+import org.yaml.snakeyaml.nodes.Tag;
+
+/**
+ * Construct standard Java classes
+ */
+public class SafeConstructor extends BaseConstructor {
+
+ public static final ConstructUndefined undefinedConstructor = new ConstructUndefined();
+
+ public SafeConstructor() {
+ this.yamlConstructors.put(Tag.NULL, new ConstructYamlNull());
+ this.yamlConstructors.put(Tag.BOOL, new ConstructYamlBool());
+ this.yamlConstructors.put(Tag.INT, new ConstructYamlInt());
+ this.yamlConstructors.put(Tag.FLOAT, new ConstructYamlFloat());
+ this.yamlConstructors.put(Tag.BINARY, new ConstructYamlBinary());
+ this.yamlConstructors.put(Tag.TIMESTAMP, new ConstructYamlTimestamp());
+ this.yamlConstructors.put(Tag.OMAP, new ConstructYamlOmap());
+ this.yamlConstructors.put(Tag.PAIRS, new ConstructYamlPairs());
+ this.yamlConstructors.put(Tag.SET, new ConstructYamlSet());
+ this.yamlConstructors.put(Tag.STR, new ConstructYamlStr());
+ this.yamlConstructors.put(Tag.SEQ, new ConstructYamlSeq());
+ this.yamlConstructors.put(Tag.MAP, new ConstructYamlMap());
+ this.yamlConstructors.put(null, undefinedConstructor);
+ this.yamlClassConstructors.put(NodeId.scalar, undefinedConstructor);
+ this.yamlClassConstructors.put(NodeId.sequence, undefinedConstructor);
+ this.yamlClassConstructors.put(NodeId.mapping, undefinedConstructor);
+ }
+
+ protected void flattenMapping(MappingNode node) {
+ // perform merging only on nodes containing merge node(s)
+ if (node.isMerged()) {
+ node.setValue(mergeNode(node, true, new HashMap<Object, Integer>(),
+ new ArrayList<NodeTuple>()));
+ }
+ }
+
+ /**
+ * Does merge for supplied mapping node.
+ *
+ * @param node
+ * where to merge
+ * @param isPreffered
+ * true if keys of node should take precedence over others...
+ * @param key2index
+ * maps already merged keys to index from values
+ * @param values
+ * collects merged NodeTuple
+ * @return list of the merged NodeTuple (to be set as value for the
+ * MappingNode)
+ */
+ private List<NodeTuple> mergeNode(MappingNode node, boolean isPreffered,
+ Map<Object, Integer> key2index, List<NodeTuple> values) {
+ List<NodeTuple> nodeValue = node.getValue();
+ // reversed for http://code.google.com/p/snakeyaml/issues/detail?id=139
+ Collections.reverse(nodeValue);
+ for (Iterator<NodeTuple> iter = nodeValue.iterator(); iter.hasNext();) {
+ final NodeTuple nodeTuple = iter.next();
+ final Node keyNode = nodeTuple.getKeyNode();
+ final Node valueNode = nodeTuple.getValueNode();
+ if (keyNode.getTag().equals(Tag.MERGE)) {
+ iter.remove();
+ switch (valueNode.getNodeId()) {
+ case mapping:
+ MappingNode mn = (MappingNode) valueNode;
+ mergeNode(mn, false, key2index, values);
+ break;
+ case sequence:
+ 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;
+ mergeNode(mnode, false, key2index, values);
+ }
+ 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 {
+ // we need to construct keys to avoid duplications
+ Object key = constructObject(keyNode);
+ if (!key2index.containsKey(key)) { // 1st time merging key
+ values.add(nodeTuple);
+ // keep track where tuple for the key is
+ key2index.put(key, values.size() - 1);
+ } else if (isPreffered) { // there is value for the key, but we
+ // need to override it
+ // change value for the key using saved position
+ values.set(key2index.get(key), nodeTuple);
+ }
+ }
+ }
+ return values;
+ }
+
+ protected void constructMapping2ndStep(MappingNode node, Map<Object, Object> mapping) {
+ flattenMapping(node);
+ super.constructMapping2ndStep(node, mapping);
+ }
+
+ @Override
+ protected void constructSet2ndStep(MappingNode node, Set<Object> set) {
+ flattenMapping(node);
+ super.constructSet2ndStep(node, set);
+ }
+
+ public class ConstructYamlNull extends AbstractConstruct {
+ 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);
+ }
+
+ public class ConstructYamlBool extends AbstractConstruct {
+ public Object construct(Node node) {
+ String val = (String) constructScalar((ScalarNode) node);
+ return BOOL_VALUES.get(val.toLowerCase());
+ }
+ }
+
+ public class ConstructYamlInt extends AbstractConstruct {
+ 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 ("0".equals(value)) {
+ return Integer.valueOf(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 {
+ result = Integer.valueOf(number, radix);
+ } catch (NumberFormatException e) {
+ try {
+ result = Long.valueOf(number, radix);
+ } catch (NumberFormatException e1) {
+ result = new BigInteger(number, radix);
+ }
+ }
+ return result;
+ }
+
+ public class ConstructYamlFloat extends AbstractConstruct {
+ 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 (".inf".equals(valLower)) {
+ return new Double(sign == -1 ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY);
+ } else if (".nan".equals(valLower)) {
+ 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 {
+ Double d = Double.valueOf(value);
+ return new Double(d.doubleValue() * sign);
+ }
+ }
+ }
+
+ public class ConstructYamlBinary extends AbstractConstruct {
+ public Object construct(Node node) {
+ byte[] decoded = Base64Coder.decode(constructScalar((ScalarNode) node).toString()
+ .toCharArray());
+ return decoded;
+ }
+ }
+
+ public class ConstructYamlNumber extends AbstractConstruct {
+
+ private final NumberFormat nf = NumberFormat.getInstance();
+
+ public Object construct(Node node) {
+ ScalarNode scalar = (ScalarNode) node;
+ try {
+ return nf.parse(scalar.getValue());
+ } catch (ParseException e) {
+ String lowerCaseValue = scalar.getValue().toLowerCase();
+ if (lowerCaseValue.contains("inf") || lowerCaseValue.contains("nan")) {
+ /*
+ * Non-finites such as (+/-)infinity and NaN are not
+ * parseable by NumberFormat when these `Double` values are
+ * dumped by snakeyaml. Delegate to the `Tag.FLOAT`
+ * constructor when for this expected failure cause.
+ */
+ return (Number) yamlConstructors.get(Tag.FLOAT).construct(node);
+ } else {
+ throw new IllegalArgumentException("Unable to parse as Number: "
+ + scalar.getValue());
+ }
+ }
+ }
+ }
+
+ 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]?)$");
+
+ public static class ConstructYamlTimestamp extends AbstractConstruct {
+ private Calendar calendar;
+
+ public Calendar getCalendar() {
+ return calendar;
+ }
+
+ public Object construct(Node node) {
+ ScalarNode scalar = (ScalarNode) node;
+ String nodeValue = scalar.getValue();
+ Matcher match = YMD_REGEXP.matcher(nodeValue);
+ if (match.matches()) {
+ String year_s = match.group(1);
+ String month_s = match.group(2);
+ String day_s = match.group(3);
+ calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
+ calendar.clear();
+ calendar.set(Calendar.YEAR, Integer.parseInt(year_s));
+ // Java's months are zero-based...
+ calendar.set(Calendar.MONTH, Integer.parseInt(month_s) - 1); // x
+ calendar.set(Calendar.DAY_OF_MONTH, Integer.parseInt(day_s));
+ return calendar.getTime();
+ } else {
+ match = TIMESTAMP_REGEXP.matcher(nodeValue);
+ if (!match.matches()) {
+ throw new YAMLException("Unexpected timestamp: " + nodeValue);
+ }
+ 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);
+ // seconds and milliseconds
+ String seconds = match.group(6);
+ String millis = match.group(7);
+ if (millis != null) {
+ seconds = seconds + "." + millis;
+ }
+ double fractions = Double.parseDouble(seconds);
+ int sec_s = (int) Math.round(Math.floor(fractions));
+ int usec = (int) Math.round((fractions - sec_s) * 1000);
+ // timezone
+ String timezoneh_s = match.group(8);
+ String timezonem_s = match.group(9);
+ TimeZone timeZone;
+ if (timezoneh_s != null) {
+ String time = timezonem_s != null ? ":" + timezonem_s : "00";
+ timeZone = TimeZone.getTimeZone("GMT" + timezoneh_s + time);
+ } else {
+ // no time zone provided
+ timeZone = TimeZone.getTimeZone("UTC");
+ }
+ calendar = Calendar.getInstance(timeZone);
+ calendar.set(Calendar.YEAR, Integer.parseInt(year_s));
+ // Java's months are zero-based...
+ calendar.set(Calendar.MONTH, Integer.parseInt(month_s) - 1);
+ calendar.set(Calendar.DAY_OF_MONTH, Integer.parseInt(day_s));
+ calendar.set(Calendar.HOUR_OF_DAY, Integer.parseInt(hour_s));
+ calendar.set(Calendar.MINUTE, Integer.parseInt(min_s));
+ calendar.set(Calendar.SECOND, sec_s);
+ calendar.set(Calendar.MILLISECOND, usec);
+ return calendar.getTime();
+ }
+ }
+ }
+
+ public class ConstructYamlOmap extends AbstractConstruct {
+ 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).getKeyNode();
+ Node valueNode = mnode.getValue().get(0).getValueNode();
+ Object key = constructObject(keyNode);
+ Object value = constructObject(valueNode);
+ omap.put(key, value);
+ }
+ return omap;
+ }
+ }
+
+ // Note: the same code as `construct_yaml_omap`.
+ public class ConstructYamlPairs extends AbstractConstruct {
+ public Object construct(Node node) {
+ // Note: we do not check for duplicate keys, because it's too
+ // CPU-expensive.
+ 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;
+ List<Object[]> pairs = new ArrayList<Object[]>(snode.getValue().size());
+ 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).getKeyNode();
+ Node valueNode = mnode.getValue().get(0).getValueNode();
+ Object key = constructObject(keyNode);
+ Object value = constructObject(valueNode);
+ pairs.add(new Object[] { key, value });
+ }
+ return pairs;
+ }
+ }
+
+ public class ConstructYamlSet implements Construct {
+ public Object construct(Node node) {
+ if (node.isTwoStepsConstruction()) {
+ return createDefaultSet();
+ } else {
+ return constructSet((MappingNode) node);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public void construct2ndStep(Node node, Object object) {
+ if (node.isTwoStepsConstruction()) {
+ constructSet2ndStep((MappingNode) node, (Set<Object>) object);
+ } else {
+ throw new YAMLException("Unexpected recursive set structure. Node: " + node);
+ }
+ }
+ }
+
+ public class ConstructYamlStr extends AbstractConstruct {
+ public Object construct(Node node) {
+ return constructScalar((ScalarNode) node);
+ }
+ }
+
+ public class ConstructYamlSeq implements Construct {
+ public Object construct(Node node) {
+ SequenceNode seqNode = (SequenceNode) node;
+ if (node.isTwoStepsConstruction()) {
+ return createDefaultList(seqNode.getValue().size());
+ } else {
+ return constructSequence(seqNode);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public void construct2ndStep(Node node, Object data) {
+ if (node.isTwoStepsConstruction()) {
+ constructSequenceStep2((SequenceNode) node, (List<Object>) data);
+ } else {
+ throw new YAMLException("Unexpected recursive sequence structure. Node: " + node);
+ }
+ }
+ }
+
+ public class ConstructYamlMap implements Construct {
+ public Object construct(Node node) {
+ if (node.isTwoStepsConstruction()) {
+ return createDefaultMap();
+ } else {
+ return constructMapping((MappingNode) node);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public void construct2ndStep(Node node, Object object) {
+ if (node.isTwoStepsConstruction()) {
+ constructMapping2ndStep((MappingNode) node, (Map<Object, Object>) object);
+ } else {
+ throw new YAMLException("Unexpected recursive mapping structure. Node: " + node);
+ }
+ }
+ }
+
+ public static final class ConstructUndefined extends AbstractConstruct {
+ 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/Emitable.java b/src/main/java/org/yaml/snakeyaml/emitter/Emitable.java
new file mode 100644
index 0000000..8773728
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/emitter/Emitable.java
@@ -0,0 +1,24 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.emitter;
+
+import java.io.IOException;
+
+import org.yaml.snakeyaml.events.Event;
+
+public interface Emitable {
+ void emit(Event event) throws IOException;
+}
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 0000000..2136e21
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/emitter/Emitter.java
@@ -0,0 +1,1479 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+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.Map;
+import java.util.Queue;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.regex.Pattern;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.DumperOptions.Version;
+import org.yaml.snakeyaml.error.YAMLException;
+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;
+import org.yaml.snakeyaml.nodes.Tag;
+import org.yaml.snakeyaml.reader.StreamReader;
+import org.yaml.snakeyaml.scanner.Constant;
+import org.yaml.snakeyaml.util.ArrayStack;
+
+/**
+ * <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>
+ */
+public final class Emitter implements Emitable {
+ 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;
+
+ private static final char[] SPACE = { ' ' };
+
+ static {
+ ESCAPE_REPLACEMENTS.put('\0', "0");
+ ESCAPE_REPLACEMENTS.put('\u0007', "a");
+ ESCAPE_REPLACEMENTS.put('\u0008', "b");
+ ESCAPE_REPLACEMENTS.put('\u0009', "t");
+ ESCAPE_REPLACEMENTS.put('\n', "n");
+ ESCAPE_REPLACEMENTS.put('\u000B', "v");
+ ESCAPE_REPLACEMENTS.put('\u000C', "f");
+ ESCAPE_REPLACEMENTS.put('\r', "r");
+ ESCAPE_REPLACEMENTS.put('\u001B', "e");
+ ESCAPE_REPLACEMENTS.put('"', "\"");
+ ESCAPE_REPLACEMENTS.put('\\', "\\");
+ ESCAPE_REPLACEMENTS.put('\u0085', "N");
+ ESCAPE_REPLACEMENTS.put('\u00A0', "_");
+ ESCAPE_REPLACEMENTS.put('\u2028', "L");
+ ESCAPE_REPLACEMENTS.put('\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.PREFIX, "!!");
+ }
+ // 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 ArrayStack<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 ArrayStack<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; this variable is not used
+ private int column;
+ private boolean whitespace;
+ private boolean indention;
+ private boolean openEnded;
+
+ // Formatting details.
+ private Boolean canonical;
+ // pretty print flow by adding extra line breaks
+ private Boolean prettyFlow;
+
+ private boolean allowUnicode;
+ private int bestIndent;
+ private int indicatorIndent;
+ private int bestWidth;
+ private char[] bestLineBreak;
+ private boolean splitLines;
+
+ // 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 Character style;
+
+ 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 ArrayStack<EmitterState>(100);
+ this.state = new ExpectStreamStart();
+ // Current event and the event queue.
+ this.events = new ArrayBlockingQueue<Event>(100);
+ this.event = null;
+ // The current indentation level and the stack of previous indents.
+ this.indents = new ArrayStack<Integer>(10);
+ 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 ':')?
+ column = 0;
+ whitespace = true;
+ indention = true;
+
+ // Whether the document requires an explicit document indicator
+ openEnded = false;
+
+ // Formatting details.
+ this.canonical = opts.isCanonical();
+ this.prettyFlow = opts.isPrettyFlow();
+ this.allowUnicode = opts.isAllowUnicode();
+ this.bestIndent = 2;
+ if ((opts.getIndent() > MIN_INDENT) && (opts.getIndent() < MAX_INDENT)) {
+ this.bestIndent = opts.getIndent();
+ }
+ this.indicatorIndent = opts.getIndicatorIndent();
+ this.bestWidth = 80;
+ if (opts.getWidth() > this.bestIndent * 2) {
+ this.bestWidth = opts.getWidth();
+ }
+ this.bestLineBreak = opts.getLineBreak().getString().toCharArray();
+ this.splitLines = opts.getSplitLines();
+
+ // 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 = null;
+ }
+
+ public void emit(Event event) throws IOException {
+ this.events.add(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.push(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 || ev.getTags().isEmpty())
+ && !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.push(new ExpectDocumentEnd());
+ expectNode(true, false, false);
+ }
+ }
+
+ // Node handlers.
+
+ private void expectNode(boolean root, 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.pop();
+ }
+
+ private void expectScalar() throws IOException {
+ increaseIndent(true, false);
+ processScalar();
+ indent = indents.pop();
+ state = states.pop();
+ }
+
+ // Flow sequence handlers.
+
+ private void expectFlowSequence() throws IOException {
+ writeIndicator("[", true, true, false);
+ flowLevel++;
+ increaseIndent(true, false);
+ if (prettyFlow) {
+ writeIndent();
+ }
+ state = new ExpectFirstFlowSequenceItem();
+ }
+
+ private class ExpectFirstFlowSequenceItem implements EmitterState {
+ public void expect() throws IOException {
+ if (event instanceof SequenceEndEvent) {
+ indent = indents.pop();
+ flowLevel--;
+ writeIndicator("]", false, false, false);
+ state = states.pop();
+ } else {
+ if (canonical || (column > bestWidth && splitLines) || prettyFlow) {
+ writeIndent();
+ }
+ states.push(new ExpectFlowSequenceItem());
+ expectNode(false, false, false);
+ }
+ }
+ }
+
+ private class ExpectFlowSequenceItem implements EmitterState {
+ public void expect() throws IOException {
+ if (event instanceof SequenceEndEvent) {
+ indent = indents.pop();
+ flowLevel--;
+ if (canonical) {
+ writeIndicator(",", false, false, false);
+ writeIndent();
+ }
+ writeIndicator("]", false, false, false);
+ if (prettyFlow) {
+ writeIndent();
+ }
+ state = states.pop();
+ } else {
+ writeIndicator(",", false, false, false);
+ if (canonical || (column > bestWidth && splitLines) || prettyFlow) {
+ writeIndent();
+ }
+ states.push(new ExpectFlowSequenceItem());
+ expectNode(false, false, false);
+ }
+ }
+ }
+
+ // Flow mapping handlers.
+
+ private void expectFlowMapping() throws IOException {
+ writeIndicator("{", true, true, false);
+ flowLevel++;
+ increaseIndent(true, false);
+ if (prettyFlow) {
+ writeIndent();
+ }
+ state = new ExpectFirstFlowMappingKey();
+ }
+
+ private class ExpectFirstFlowMappingKey implements EmitterState {
+ public void expect() throws IOException {
+ if (event instanceof MappingEndEvent) {
+ indent = indents.pop();
+ flowLevel--;
+ writeIndicator("}", false, false, false);
+ state = states.pop();
+ } else {
+ if (canonical || (column > bestWidth && splitLines) || prettyFlow) {
+ writeIndent();
+ }
+ if (!canonical && checkSimpleKey()) {
+ states.push(new ExpectFlowMappingSimpleValue());
+ expectNode(false, true, true);
+ } else {
+ writeIndicator("?", true, false, false);
+ states.push(new ExpectFlowMappingValue());
+ expectNode(false, true, false);
+ }
+ }
+ }
+ }
+
+ private class ExpectFlowMappingKey implements EmitterState {
+ public void expect() throws IOException {
+ if (event instanceof MappingEndEvent) {
+ indent = indents.pop();
+ flowLevel--;
+ if (canonical) {
+ writeIndicator(",", false, false, false);
+ writeIndent();
+ }
+ if (prettyFlow) {
+ writeIndent();
+ }
+ writeIndicator("}", false, false, false);
+ state = states.pop();
+ } else {
+ writeIndicator(",", false, false, false);
+ if (canonical || (column > bestWidth && splitLines) || prettyFlow) {
+ writeIndent();
+ }
+ if (!canonical && checkSimpleKey()) {
+ states.push(new ExpectFlowMappingSimpleValue());
+ expectNode(false, true, true);
+ } else {
+ writeIndicator("?", true, false, false);
+ states.push(new ExpectFlowMappingValue());
+ expectNode(false, true, false);
+ }
+ }
+ }
+ }
+
+ private class ExpectFlowMappingSimpleValue implements EmitterState {
+ public void expect() throws IOException {
+ writeIndicator(":", false, false, false);
+ states.push(new ExpectFlowMappingKey());
+ expectNode(false, true, false);
+ }
+ }
+
+ private class ExpectFlowMappingValue implements EmitterState {
+ public void expect() throws IOException {
+ if (canonical || (column > bestWidth) || prettyFlow) {
+ writeIndent();
+ }
+ writeIndicator(":", true, false, false);
+ states.push(new ExpectFlowMappingKey());
+ expectNode(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.pop();
+ state = states.pop();
+ } else {
+ writeIndent();
+ writeWhitespace(indicatorIndent);
+ writeIndicator("-", true, false, true);
+ states.push(new ExpectBlockSequenceItem(false));
+ expectNode(false, 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.pop();
+ state = states.pop();
+ } else {
+ writeIndent();
+ if (checkSimpleKey()) {
+ states.push(new ExpectBlockMappingSimpleValue());
+ expectNode(false, true, true);
+ } else {
+ writeIndicator("?", true, false, true);
+ states.push(new ExpectBlockMappingValue());
+ expectNode(false, true, false);
+ }
+ }
+ }
+ }
+
+ private class ExpectBlockMappingSimpleValue implements EmitterState {
+ public void expect() throws IOException {
+ writeIndicator(":", false, false, false);
+ states.push(new ExpectBlockMappingKey(false));
+ expectNode(false, true, false);
+ }
+ }
+
+ private class ExpectBlockMappingValue implements EmitterState {
+ public void expect() throws IOException {
+ writeIndent();
+ writeIndicator(":", true, false, true);
+ states.push(new ExpectBlockMappingKey(false));
+ expectNode(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().length() == 0;
+ }
+ 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());
+ }
+ 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 == null) {
+ style = chooseScalarStyle();
+ }
+ if ((!canonical || tag == null) && ((style == null && ev.getImplicit()
+ .canOmitTagInPlainScalar()) || (style != null && ev.getImplicit()
+ .canOmitTagInNonPlainScalar()))) {
+ preparedTag = null;
+ return;
+ }
+ if (ev.getImplicit().canOmitTagInPlainScalar() && 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);
+ }
+ writeIndicator(preparedTag, true, false, false);
+ preparedTag = null;
+ }
+
+ private Character 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().canOmitTagInPlainScalar()) {
+ if (!(simpleKeyContext && (analysis.empty || analysis.multiline))
+ && ((flowLevel != 0 && analysis.allowFlowPlain) || (flowLevel == 0 && analysis.allowBlockPlain))) {
+ return null;
+ }
+ }
+ 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 == null) {
+ style = chooseScalarStyle();
+ }
+ boolean split = !simpleKeyContext && splitLines;
+ if (style == null) {
+ writePlain(analysis.scalar, split);
+ } else {
+ switch (style) {
+ case '"':
+ writeDoubleQuoted(analysis.scalar, split);
+ break;
+ case '\'':
+ writeSingleQuoted(analysis.scalar, split);
+ break;
+ case '>':
+ writeFolded(analysis.scalar, split);
+ break;
+ case '|':
+ writeLiteral(analysis.scalar);
+ break;
+ default:
+ throw new YAMLException("Unexpected style: " + style);
+ }
+ }
+ analysis = null;
+ style = null;
+ }
+
+ // Analyzers.
+
+ private String prepareVersion(Version version) {
+ if (version.major() != 1) {
+ throw new EmitterException("unsupported YAML version: " + version);
+ }
+ return version.getRepresentation();
+ }
+
+ private final static Pattern HANDLE_FORMAT = Pattern.compile("^![-_\\w]*!$");
+
+ private String prepareTagHandle(String handle) {
+ if (handle.length() == 0) {
+ 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.length() == 0) {
+ throw new EmitterException("tag prefix must not be empty");
+ }
+ StringBuilder chunks = new StringBuilder();
+ 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.length() == 0) {
+ throw new EmitterException("tag must not be empty");
+ }
+ if ("!".equals(tag)) {
+ return tag;
+ }
+ String handle = null;
+ String suffix = tag;
+ // shall the tag prefixes be sorted as in PyYAML?
+ for (String prefix : tagPrefixes.keySet()) {
+ if (tag.startsWith(prefix) && ("!".equals(prefix) || prefix.length() < tag.length())) {
+ handle = prefix;
+ }
+ }
+ if (handle != null) {
+ suffix = tag.substring(handle.length());
+ handle = tagPrefixes.get(handle);
+ }
+
+ int end = suffix.length();
+ String suffixText = end > 0 ? suffix.substring(0, end) : "";
+
+ if (handle != null) {
+ return handle + suffixText;
+ }
+ return "!<" + suffixText + ">";
+ }
+
+ private final static Pattern ANCHOR_FORMAT = Pattern.compile("^[-_\\w]*$");
+
+ static String prepareAnchor(String anchor) {
+ if (anchor.length() == 0) {
+ 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.length() == 0) {
+ return new ScalarAnalysis(scalar, true, false, false, 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 || Constant.NULL_BL_T_LINEBR.has(scalar.charAt(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.
+ boolean isLineBreak = Constant.LINEBR.has(ch);
+ if (isLineBreak) {
+ 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 (isLineBreak) {
+ 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 = Constant.NULL_BL_T.has(ch) || isLineBreak;
+ followedByWhitespace = index + 1 >= scalar.length()
+ || (Constant.NULL_BL_T.has(scalar.charAt(index + 1))) || isLineBreak;
+ }
+ // Let's decide what styles are allowed.
+ boolean allowFlowPlain = true;
+ boolean allowBlockPlain = true;
+ boolean allowSingleQuoted = 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 in the flow context.
+ if (lineBreaks) {
+ allowFlowPlain = 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, 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 {
+ if (!this.whitespace && needWhitespace) {
+ this.column++;
+ stream.write(SPACE);
+ }
+ this.whitespace = whitespace;
+ this.indention = this.indention && indentation;
+ this.column += indicator.length();
+ openEnded = false;
+ stream.write(indicator);
+ }
+
+ 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);
+ }
+
+ writeWhitespace(indent - this.column);
+ }
+
+ private void writeWhitespace(int length) throws IOException {
+ if (length <= 0) {
+ return;
+ }
+ this.whitespace = true;
+ char[] data = new char[length];
+ for (int i = 0; i < data.length; i++) {
+ data[i] = ' ';
+ }
+ this.column += length;
+ stream.write(data);
+ }
+
+ private void writeLineBreak(String data) throws IOException {
+ this.whitespace = true;
+ this.indention = true;
+ this.column = 0;
+ if (data == null) {
+ stream.write(this.bestLineBreak);
+ } else {
+ stream.write(data);
+ }
+ }
+
+ void writeVersionDirective(String versionText) throws IOException {
+ stream.write("%YAML ");
+ stream.write(versionText);
+ writeLineBreak(null);
+ }
+
+ void writeTagDirective(String handleText, String prefixText) throws IOException {
+ // XXX: not sure 4 invocations better then StringBuilders created by str
+ // + str
+ stream.write("%TAG ");
+ stream.write(handleText);
+ stream.write(SPACE);
+ stream.write(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 {
+ int len = end - start;
+ this.column += len;
+ stream.write(text, start, len);
+ }
+ start = end;
+ }
+ } else if (breaks) {
+ if (ch == 0 || Constant.LINEBR.hasNo(ch)) {
+ 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 (Constant.LINEBR.has(ch, "\0 \'")) {
+ if (start < end) {
+ int len = end - start;
+ this.column += len;
+ stream.write(text, start, len);
+ start = end;
+ }
+ }
+ }
+ if (ch == '\'') {
+ this.column += 2;
+ stream.write("''");
+ start = end + 1;
+ }
+ if (ch != 0) {
+ spaces = ch == ' ';
+ breaks = Constant.LINEBR.has(ch);
+ }
+ 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) {
+ int len = end - start;
+ this.column += len;
+ stream.write(text, start, len);
+ start = end;
+ }
+ if (ch != null) {
+ String data;
+ if (ESCAPE_REPLACEMENTS.containsKey(ch)) {
+ data = "\\" + ESCAPE_REPLACEMENTS.get(ch);
+ } else if (!this.allowUnicode || !StreamReader.isPrintable(ch)) {
+ // if !allowUnicode or the character is not printable,
+ // we must encode it
+ if (ch <= '\u00FF') {
+ String s = "0" + Integer.toString(ch, 16);
+ data = "\\x" + s.substring(s.length() - 2);
+ } else if (ch >= '\uD800' && ch <= '\uDBFF') {
+ if (end + 1 < text.length()) {
+ Character ch2 = text.charAt(++end);
+ String s = "000" + Long.toHexString(Character.toCodePoint(ch, ch2));
+ data = "\\U" + s.substring(s.length() - 8);
+ } else {
+ String s = "000" + Integer.toString(ch, 16);
+ data = "\\u" + s.substring(s.length() - 4);
+ }
+ } else {
+ String s = "000" + Integer.toString(ch, 16);
+ data = "\\u" + s.substring(s.length() - 4);
+ }
+ } else {
+ data = String.valueOf(ch);
+ }
+ 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) {
+ StringBuilder hints = new StringBuilder();
+ if (Constant.LINEBR.has(text.charAt(0), " ")) {
+ hints.append(bestIndent);
+ }
+ char ch1 = text.charAt(text.length() - 1);
+ if (Constant.LINEBR.hasNo(ch1)) {
+ hints.append("-");
+ } else if (text.length() == 1 || Constant.LINEBR.has(text.charAt(text.length() - 2))) {
+ hints.append("+");
+ }
+ return hints.toString();
+ }
+
+ void writeFolded(String text, boolean split) 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 || Constant.LINEBR.hasNo(ch)) {
+ 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 && split) {
+ writeIndent();
+ } else {
+ int len = end - start;
+ this.column += len;
+ stream.write(text, start, len);
+ }
+ start = end;
+ }
+ } else {
+ if (Constant.LINEBR.has(ch, "\0 ")) {
+ int len = end - start;
+ this.column += len;
+ stream.write(text, start, len);
+ if (ch == 0) {
+ writeLineBreak(null);
+ }
+ start = end;
+ }
+ }
+ if (ch != 0) {
+ breaks = Constant.LINEBR.has(ch);
+ 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 || Constant.LINEBR.hasNo(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 (ch == 0 || Constant.LINEBR.has(ch)) {
+ stream.write(text, start, end - start);
+ if (ch == 0) {
+ writeLineBreak(null);
+ }
+ start = end;
+ }
+ }
+ if (ch != 0) {
+ breaks = Constant.LINEBR.has(ch);
+ }
+ end++;
+ }
+ }
+
+ void writePlain(String text, boolean split) throws IOException {
+ if (rootContext) {
+ openEnded = true;
+ }
+ if (text.length() == 0) {
+ return;
+ }
+ if (!this.whitespace) {
+ this.column++;
+ stream.write(SPACE);
+ }
+ 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 {
+ int len = end - start;
+ this.column += len;
+ stream.write(text, start, len);
+ }
+ start = end;
+ }
+ } else if (breaks) {
+ if (Constant.LINEBR.hasNo(ch)) {
+ 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 || Constant.LINEBR.has(ch)) {
+ int len = end - start;
+ this.column += len;
+ stream.write(text, start, len);
+ start = end;
+ }
+ }
+ if (ch != 0) {
+ spaces = ch == ' ';
+ breaks = Constant.LINEBR.has(ch);
+ }
+ 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 0000000..ed83fee
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/emitter/EmitterException.java
@@ -0,0 +1,26 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.emitter;
+
+import org.yaml.snakeyaml.error.YAMLException;
+
+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 0000000..8e6622e
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/emitter/EmitterState.java
@@ -0,0 +1,25 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.emitter;
+
+import java.io.IOException;
+
+/**
+ * Python's methods are first class object. Java needs a class.
+ */
+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 0000000..99a0829
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/emitter/ScalarAnalysis.java
@@ -0,0 +1,37 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.emitter;
+
+public final class ScalarAnalysis {
+ public String scalar;
+ public boolean empty;
+ public boolean multiline;
+ public boolean allowFlowPlain;
+ public boolean allowBlockPlain;
+ public boolean allowSingleQuoted;
+ public boolean allowBlock;
+
+ public ScalarAnalysis(String scalar, boolean empty, boolean multiline, boolean allowFlowPlain,
+ boolean allowBlockPlain, boolean allowSingleQuoted, boolean allowBlock) {
+ this.scalar = scalar;
+ this.empty = empty;
+ this.multiline = multiline;
+ this.allowFlowPlain = allowFlowPlain;
+ this.allowBlockPlain = allowBlockPlain;
+ this.allowSingleQuoted = allowSingleQuoted;
+ 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 0000000..7e1d546
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/error/Mark.java
@@ -0,0 +1,132 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.error;
+
+import org.yaml.snakeyaml.scanner.Constant;
+
+/**
+ * It's just a record and its only use is producing nice error messages. Parser
+ * does not use it for any other purposes.
+ */
+public final class Mark {
+ private String name;
+ private int index;
+ 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.index = index;
+ this.line = line;
+ this.column = column;
+ this.buffer = buffer;
+ this.pointer = pointer;
+ }
+
+ private boolean isLineBreak(char ch) {
+ return Constant.NULL_OR_LINEBR.has(ch);
+ }
+
+ 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);
+ StringBuilder result = new StringBuilder();
+ 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();
+ StringBuilder where = new StringBuilder(" in ");
+ where.append(name);
+ where.append(", line ");
+ where.append(line + 1);
+ where.append(", column ");
+ where.append(column + 1);
+ if (snippet != null) {
+ where.append(":\n");
+ where.append(snippet);
+ }
+ return where.toString();
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * starts with 0
+ */
+ public int getLine() {
+ return line;
+ }
+
+ /**
+ * starts with 0
+ */
+ public int getColumn() {
+ return column;
+ }
+
+ /**
+ * starts with 0
+ */
+ public int getIndex() {
+ return index;
+ }
+
+}
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 0000000..4e44ab9
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/error/MarkedYAMLException.java
@@ -0,0 +1,101 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.error;
+
+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) {
+ this(context, contextMark, problem, problemMark, note, null);
+ }
+
+ protected MarkedYAMLException(String context, Mark contextMark, String problem,
+ Mark problemMark, String note, Throwable cause) {
+ super(context + "; " + problem + "; " + problemMark, cause);
+ 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, null);
+ }
+
+ protected MarkedYAMLException(String context, Mark contextMark, String problem,
+ Mark problemMark, Throwable cause) {
+ this(context, contextMark, problem, problemMark, null, cause);
+ }
+
+ @Override
+ public String getMessage() {
+ return toString();
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder lines = new StringBuilder();
+ if (context != null) {
+ lines.append(context);
+ lines.append("\n");
+ }
+ if (contextMark != null
+ && (problem == null || problemMark == null
+ || contextMark.getName().equals(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();
+ }
+
+ public String getContext() {
+ return context;
+ }
+
+ public Mark getContextMark() {
+ return contextMark;
+ }
+
+ public String getProblem() {
+ return problem;
+ }
+
+ public Mark getProblemMark() {
+ return problemMark;
+ }
+}
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 0000000..af7189b
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/error/YAMLException.java
@@ -0,0 +1,32 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.error;
+
+public class YAMLException extends RuntimeException {
+ private static final long serialVersionUID = -4738336175050337570L;
+
+ public YAMLException(String message) {
+ super(message);
+ }
+
+ public YAMLException(Throwable cause) {
+ super(cause);
+ }
+
+ public YAMLException(String message, Throwable cause) {
+ super(message, 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 0000000..e0dcf7f
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/events/AliasEvent.java
@@ -0,0 +1,32 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.events;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * Marks the inclusion of a previously anchored node.
+ */
+public final class AliasEvent extends NodeEvent {
+ public AliasEvent(String anchor, Mark startMark, Mark endMark) {
+ super(anchor, startMark, endMark);
+ }
+
+ @Override
+ public boolean is(Event.ID id) {
+ return ID.Alias == id;
+ }
+}
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 0000000..b36f32c
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/events/CollectionEndEvent.java
@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.events;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * Base class for the end events of the collection nodes.
+ */
+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 0000000..9a77299
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/events/CollectionStartEvent.java
@@ -0,0 +1,73 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.events;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * Base class for the start events of the collection nodes.
+ */
+public abstract class CollectionStartEvent extends NodeEvent {
+ private final String tag;
+ // The implicit flag of a collection start event indicates if the tag may be
+ // omitted when the collection is emitted
+ private final boolean implicit;
+ // flag indicates if a collection is block or flow
+ 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;
+ }
+
+ /**
+ * Tag of this collection.
+ *
+ * @return The tag of this collection, or <code>null</code> if no explicit
+ * tag is available.
+ */
+ public String getTag() {
+ return this.tag;
+ }
+
+ /**
+ * <code>true</code> if the tag can be omitted while this collection is
+ * emitted.
+ *
+ * @return True if the tag can be omitted while this collection is emitted.
+ */
+ public boolean getImplicit() {
+ return this.implicit;
+ }
+
+ /**
+ * <code>true</code> if this collection is in flow style, <code>false</code>
+ * for block style.
+ *
+ * @return If this collection is in flow style.
+ */
+ 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 0000000..30fe439
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/events/DocumentEndEvent.java
@@ -0,0 +1,42 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.events;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * Marks the end of a document.
+ * <p>
+ * This event follows the document's content.
+ * </p>
+ */
+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;
+ }
+
+ @Override
+ public boolean is(Event.ID id) {
+ return ID.DocumentEnd == id;
+ }
+}
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 0000000..fa24cdf
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/events/DocumentStartEvent.java
@@ -0,0 +1,76 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.events;
+
+import java.util.Map;
+
+import org.yaml.snakeyaml.DumperOptions.Version;
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * Marks the beginning of a document.
+ * <p>
+ * This event followed by the document's content and a {@link DocumentEndEvent}.
+ * </p>
+ */
+public final class DocumentStartEvent extends Event {
+ private final boolean explicit;
+ private final Version version;
+ private final Map<String, String> tags;
+
+ public DocumentStartEvent(Mark startMark, Mark endMark, boolean explicit, Version version,
+ Map<String, String> tags) {
+ super(startMark, endMark);
+ this.explicit = explicit;
+ this.version = version;
+ // TODO enforce not null
+ // if (tags == null) {
+ // throw new NullPointerException("Tags must be provided.");
+ // }
+ this.tags = tags;
+ }
+
+ public boolean getExplicit() {
+ return explicit;
+ }
+
+ /**
+ * YAML version the document conforms to.
+ *
+ * @return <code>null</code>if the document has no explicit
+ * <code>%YAML</code> directive. Otherwise an array with two
+ * components, the major and minor part of the version (in this
+ * order).
+ */
+ public Version getVersion() {
+ return version;
+ }
+
+ /**
+ * Tag shorthands as defined by the <code>%TAG</code> directive.
+ *
+ * @return Mapping of 'handles' to 'prefixes' (the handles include the '!'
+ * characters).
+ */
+ public Map<String, String> getTags() {
+ return tags;
+ }
+
+ @Override
+ public boolean is(Event.ID id) {
+ return ID.DocumentStart == id;
+ }
+}
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 0000000..4ebfa92
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/events/Event.java
@@ -0,0 +1,77 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.events;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * Basic unit of output from a {@link org.yaml.snakeyaml.parser.Parser} or input
+ * of a {@link org.yaml.snakeyaml.emitter.Emitter}.
+ */
+public abstract class Event {
+ public enum ID {
+ Alias, DocumentEnd, DocumentStart, MappingEnd, MappingStart, Scalar, SequenceEnd, SequenceStart, StreamEnd, StreamStart
+ }
+
+ 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 "";
+ }
+
+ public abstract boolean is(Event.ID id);
+
+ /*
+ * for tests only
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof Event) {
+ return toString().equals(obj.toString());
+ } else {
+ return false;
+ }
+ }
+
+ /*
+ * for tests only
+ */
+ @Override
+ public int hashCode() {
+ return toString().hashCode();
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/events/ImplicitTuple.java b/src/main/java/org/yaml/snakeyaml/events/ImplicitTuple.java
new file mode 100644
index 0000000..86a99ac
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/events/ImplicitTuple.java
@@ -0,0 +1,58 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.events;
+
+/**
+ * The implicit flag of a scalar event is a pair of boolean values that indicate
+ * if the tag may be omitted when the scalar is emitted in a plain and non-plain
+ * style correspondingly.
+ *
+ * @see <a href="http://pyyaml.org/wiki/PyYAMLDocumentation#Events">Events</a>
+ */
+public class ImplicitTuple {
+ private final boolean plain;
+ private final boolean nonPlain;
+
+ public ImplicitTuple(boolean plain, boolean nonplain) {
+ this.plain = plain;
+ this.nonPlain = nonplain;
+ }
+
+ /**
+ * @return true when tag may be omitted when the scalar is emitted in a
+ * plain style.
+ */
+ public boolean canOmitTagInPlainScalar() {
+ return plain;
+ }
+
+ /**
+ * @return true when tag may be omitted when the scalar is emitted in a
+ * non-plain style.
+ */
+ public boolean canOmitTagInNonPlainScalar() {
+ return nonPlain;
+ }
+
+ public boolean bothFalse() {
+ return !plain && !nonPlain;
+ }
+
+ @Override
+ public String toString() {
+ return "implicit=[" + plain + ", " + nonPlain + "]";
+ }
+}
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 0000000..618c916
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/events/MappingEndEvent.java
@@ -0,0 +1,35 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.events;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * Marks the end of a mapping node.
+ *
+ * @see MappingStartEvent
+ */
+public final class MappingEndEvent extends CollectionEndEvent {
+
+ public MappingEndEvent(Mark startMark, Mark endMark) {
+ super(startMark, endMark);
+ }
+
+ @Override
+ public boolean is(Event.ID id) {
+ return ID.MappingEnd == id;
+ }
+}
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 0000000..412e4d5
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/events/MappingStartEvent.java
@@ -0,0 +1,44 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.events;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * Marks the beginning of a mapping node.
+ * <p>
+ * This event is followed by a number of key value pairs. <br>
+ * The pairs are not in any particular order. However, the value always directly
+ * follows the corresponding key. <br>
+ * After the key value pairs follows a {@link MappingEndEvent}.
+ * </p>
+ * <p>
+ * There must be an even number of node events between the start and end event.
+ * </p>
+ *
+ * @see MappingEndEvent
+ */
+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);
+ }
+
+ @Override
+ public boolean is(Event.ID id) {
+ return ID.MappingStart == id;
+ }
+}
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 0000000..f0af48b
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/events/NodeEvent.java
@@ -0,0 +1,49 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.events;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * Base class for all events that mark the beginning of a node.
+ */
+public abstract class NodeEvent extends Event {
+
+ private final String anchor;
+
+ public NodeEvent(String anchor, Mark startMark, Mark endMark) {
+ super(startMark, endMark);
+ this.anchor = anchor;
+ }
+
+ /**
+ * Node anchor by which this node might later be referenced by a
+ * {@link AliasEvent}.
+ * <p>
+ * Note that {@link AliasEvent}s are by it self <code>NodeEvent</code>s and
+ * use this property to indicate the referenced anchor.
+ *
+ * @return Anchor of this node or <code>null</code> if no anchor is defined.
+ */
+ 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 0000000..7f07a62
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/events/ScalarEvent.java
@@ -0,0 +1,101 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.events;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * Marks a scalar value.
+ */
+public final class ScalarEvent extends NodeEvent {
+ private final String tag;
+ // style flag of a scalar event indicates the style of the scalar. Possible
+ // values are None, '', '\'', '"', '|', '>'
+ private final Character style;
+ private final String value;
+ // The implicit flag of a scalar event is a pair of boolean values that
+ // indicate if the tag may be omitted when the scalar is emitted in a plain
+ // and non-plain style correspondingly.
+ private final ImplicitTuple implicit;
+
+ public ScalarEvent(String anchor, String tag, ImplicitTuple 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;
+ }
+
+ /**
+ * Tag of this scalar.
+ *
+ * @return The tag of this scalar, or <code>null</code> if no explicit tag
+ * is available.
+ */
+ public String getTag() {
+ return this.tag;
+ }
+
+ /**
+ * Style of the scalar.
+ * <dl>
+ * <dt>null</dt>
+ * <dd>Flow Style - Plain</dd>
+ * <dt>'\''</dt>
+ * <dd>Flow Style - Single-Quoted</dd>
+ * <dt>'"'</dt>
+ * <dd>Flow Style - Double-Quoted</dd>
+ * <dt>'|'</dt>
+ * <dd>Block Style - Literal</dd>
+ * <dt>'>'</dt>
+ * <dd>Block Style - Folded</dd>
+ * </dl>
+ *
+ * @see <a href="http://yaml.org/spec/1.1/#id864487">Kind/Style
+ * Combinations</a>
+ * @return Style of the scalar.
+ */
+ public Character getStyle() {
+ return this.style;
+ }
+
+ /**
+ * String representation of the value.
+ * <p>
+ * Without quotes and escaping.
+ * </p>
+ *
+ * @return Value as Unicode string.
+ */
+ public String getValue() {
+ return this.value;
+ }
+
+ public ImplicitTuple getImplicit() {
+ return this.implicit;
+ }
+
+ @Override
+ protected String getArguments() {
+ return super.getArguments() + ", tag=" + tag + ", " + implicit + ", value=" + value;
+ }
+
+ @Override
+ public boolean is(Event.ID id) {
+ return ID.Scalar == id;
+ }
+}
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 0000000..a6a6127
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/events/SequenceEndEvent.java
@@ -0,0 +1,35 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.events;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * Marks the end of a sequence.
+ *
+ * @see SequenceStartEvent
+ */
+public final class SequenceEndEvent extends CollectionEndEvent {
+
+ public SequenceEndEvent(Mark startMark, Mark endMark) {
+ super(startMark, endMark);
+ }
+
+ @Override
+ public boolean is(Event.ID id) {
+ return ID.SequenceEnd == id;
+ }
+}
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 0000000..eb7b910
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/events/SequenceStartEvent.java
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.events;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * Marks the beginning of a sequence node.
+ * <p>
+ * This event is followed by the elements contained in the sequence, and a
+ * {@link SequenceEndEvent}.
+ * </p>
+ *
+ * @see SequenceEndEvent
+ */
+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);
+ }
+
+ @Override
+ public boolean is(Event.ID id) {
+ return ID.SequenceStart == id;
+ }
+}
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 0000000..1389c6b
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/events/StreamEndEvent.java
@@ -0,0 +1,40 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.events;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * Marks the end of a stream that might have contained multiple documents.
+ * <p>
+ * This event is the last event that a parser emits. Together with
+ * {@link StreamStartEvent} (which is the first event a parser emits) they mark
+ * the beginning and the end of a stream of documents.
+ * </p>
+ * <p>
+ * See {@link Event} for an exemplary output.
+ * </p>
+ */
+public final class StreamEndEvent extends Event {
+ public StreamEndEvent(Mark startMark, Mark endMark) {
+ super(startMark, endMark);
+ }
+
+ @Override
+ public boolean is(Event.ID id) {
+ return ID.StreamEnd == id;
+ }
+}
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 0000000..42e6c76
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/events/StreamStartEvent.java
@@ -0,0 +1,41 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.events;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * Marks the start of a stream that might contain multiple documents.
+ * <p>
+ * This event is the first event that a parser emits. Together with
+ * {@link StreamEndEvent} (which is the last event a parser emits) they mark the
+ * beginning and the end of a stream of documents.
+ * </p>
+ * <p>
+ * See {@link Event} for an exemplary output.
+ * </p>
+ */
+public final class StreamStartEvent extends Event {
+
+ public StreamStartEvent(Mark startMark, Mark endMark) {
+ super(startMark, endMark);
+ }
+
+ @Override
+ public boolean is(Event.ID id) {
+ return ID.StreamStart == id;
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/extensions/compactnotation/CompactConstructor.java b/src/main/java/org/yaml/snakeyaml/extensions/compactnotation/CompactConstructor.java
new file mode 100644
index 0000000..ec8f1b6
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/extensions/compactnotation/CompactConstructor.java
@@ -0,0 +1,236 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.extensions.compactnotation;
+
+import java.beans.IntrospectionException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.yaml.snakeyaml.constructor.Construct;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.error.YAMLException;
+import org.yaml.snakeyaml.introspector.Property;
+import org.yaml.snakeyaml.nodes.MappingNode;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.NodeTuple;
+import org.yaml.snakeyaml.nodes.ScalarNode;
+import org.yaml.snakeyaml.nodes.SequenceNode;
+
+/**
+ * Construct a custom Java instance out of a compact object notation format.
+ */
+public class CompactConstructor extends Constructor {
+ private static final Pattern GUESS_COMPACT = Pattern
+ .compile("\\p{Alpha}.*\\s*\\((?:,?\\s*(?:(?:\\w*)|(?:\\p{Alpha}\\w*\\s*=.+))\\s*)+\\)");
+ private static final Pattern FIRST_PATTERN = Pattern.compile("(\\p{Alpha}.*)(\\s*)\\((.*?)\\)");
+ private static final Pattern PROPERTY_NAME_PATTERN = Pattern
+ .compile("\\s*(\\p{Alpha}\\w*)\\s*=(.+)");
+ private Construct compactConstruct;
+
+ protected Object constructCompactFormat(ScalarNode node, CompactData data) {
+ try {
+ Object obj = createInstance(node, data);
+ Map<String, Object> properties = new HashMap<String, Object>(data.getProperties());
+ setProperties(obj, properties);
+ return obj;
+ } catch (Exception e) {
+ throw new YAMLException(e);
+ }
+ }
+
+ protected Object createInstance(ScalarNode node, CompactData data) throws Exception {
+ Class<?> clazz = getClassForName(data.getPrefix());
+ Class<?>[] args = new Class[data.getArguments().size()];
+ for (int i = 0; i < args.length; i++) {
+ // assume all the arguments are Strings
+ args[i] = String.class;
+ }
+ java.lang.reflect.Constructor<?> c = clazz.getDeclaredConstructor(args);
+ c.setAccessible(true);
+ return c.newInstance(data.getArguments().toArray());
+
+ }
+
+ protected void setProperties(Object bean, Map<String, Object> data) throws Exception {
+ if (data == null) {
+ throw new NullPointerException("Data for Compact Object Notation cannot be null.");
+ }
+ for (Map.Entry<String, Object> entry : data.entrySet()) {
+ String key = entry.getKey();
+ Property property = getPropertyUtils().getProperty(bean.getClass(), key);
+ try {
+ property.set(bean, entry.getValue());
+ } catch (IllegalArgumentException e) {
+ throw new YAMLException("Cannot set property='" + key + "' with value='"
+ + data.get(key) + "' (" + data.get(key).getClass() + ") in " + bean);
+ }
+ }
+ }
+
+ public CompactData getCompactData(String scalar) {
+ if (!scalar.endsWith(")")) {
+ return null;
+ }
+ if (scalar.indexOf('(') < 0) {
+ return null;
+ }
+ Matcher m = FIRST_PATTERN.matcher(scalar);
+ if (m.matches()) {
+ String tag = m.group(1).trim();
+ String content = m.group(3);
+ CompactData data = new CompactData(tag);
+ if (content.length() == 0)
+ return data;
+ String[] names = content.split("\\s*,\\s*");
+ for (int i = 0; i < names.length; i++) {
+ String section = names[i];
+ if (section.indexOf('=') < 0) {
+ data.getArguments().add(section);
+ } else {
+ Matcher sm = PROPERTY_NAME_PATTERN.matcher(section);
+ if (sm.matches()) {
+ String name = sm.group(1);
+ String value = sm.group(2).trim();
+ data.getProperties().put(name, value);
+ } else {
+ return null;
+ }
+ }
+ }
+ return data;
+ }
+ return null;
+ }
+
+ private Construct getCompactConstruct() {
+ if (compactConstruct == null) {
+ compactConstruct = createCompactConstruct();
+ }
+ return compactConstruct;
+ }
+
+ protected Construct createCompactConstruct() {
+ return new ConstructCompactObject();
+ }
+
+ @Override
+ protected Construct getConstructor(Node node) {
+ if (node instanceof MappingNode) {
+ MappingNode mnode = (MappingNode) node;
+ List<NodeTuple> list = mnode.getValue();
+ if (list.size() == 1) {
+ NodeTuple tuple = list.get(0);
+ Node key = tuple.getKeyNode();
+ if (key instanceof ScalarNode) {
+ ScalarNode scalar = (ScalarNode) key;
+ if (GUESS_COMPACT.matcher(scalar.getValue()).matches()) {
+ return getCompactConstruct();
+ }
+ }
+ }
+ } else if (node instanceof ScalarNode) {
+ ScalarNode scalar = (ScalarNode) node;
+ if (GUESS_COMPACT.matcher(scalar.getValue()).matches()) {
+ return getCompactConstruct();
+ }
+ }
+ return super.getConstructor(node);
+ }
+
+ public class ConstructCompactObject extends ConstructMapping {
+
+ @Override
+ public void construct2ndStep(Node node, Object object) {
+ // Compact Object Notation may contain only one entry
+ MappingNode mnode = (MappingNode) node;
+ NodeTuple nodeTuple = mnode.getValue().iterator().next();
+
+ Node valueNode = nodeTuple.getValueNode();
+
+ if (valueNode instanceof MappingNode) {
+ valueNode.setType(object.getClass());
+ constructJavaBean2ndStep((MappingNode) valueNode, object);
+ } else {
+ // value is a list
+ applySequence(object, constructSequence((SequenceNode) valueNode));
+ }
+ }
+
+ /*
+ * MappingNode and ScalarNode end up here only they assumed to be a
+ * compact object's representation (@see getConstructor(Node) above)
+ */
+ public Object construct(Node node) {
+ ScalarNode tmpNode = null;
+ if (node instanceof MappingNode) {
+ // Compact Object Notation may contain only one entry
+ MappingNode mnode = (MappingNode) node;
+ NodeTuple nodeTuple = mnode.getValue().iterator().next();
+ node.setTwoStepsConstruction(true);
+ tmpNode = (ScalarNode) nodeTuple.getKeyNode();
+ // return constructScalar((ScalarNode) keyNode);
+ } else {
+ tmpNode = (ScalarNode) node;
+ }
+
+ CompactData data = getCompactData(tmpNode.getValue());
+ if (data == null) { // TODO: Should we throw an exception here ?
+ return constructScalar(tmpNode);
+ }
+ return constructCompactFormat(tmpNode, data);
+ }
+ }
+
+ protected void applySequence(Object bean, List<?> value) {
+ try {
+ Property property = getPropertyUtils().getProperty(bean.getClass(),
+ getSequencePropertyName(bean.getClass()));
+ property.set(bean, value);
+ } catch (Exception e) {
+ throw new YAMLException(e);
+ }
+ }
+
+ /**
+ * Provide the name of the property which is used when the entries form a
+ * sequence. The property must be a List.
+ *
+ * @throws IntrospectionException
+ */
+ protected String getSequencePropertyName(Class<?> bean) throws IntrospectionException {
+ Set<Property> properties = getPropertyUtils().getProperties(bean);
+ for (Iterator<Property> iterator = properties.iterator(); iterator.hasNext();) {
+ Property property = iterator.next();
+ if (!List.class.isAssignableFrom(property.getType())) {
+ iterator.remove();
+ }
+ }
+ if (properties.size() == 0) {
+ throw new YAMLException("No list property found in " + bean);
+ } else if (properties.size() > 1) {
+ throw new YAMLException(
+ "Many list properties found in "
+ + bean
+ + "; Please override getSequencePropertyName() to specify which property to use.");
+ }
+ return properties.iterator().next().getName();
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/extensions/compactnotation/CompactData.java b/src/main/java/org/yaml/snakeyaml/extensions/compactnotation/CompactData.java
new file mode 100644
index 0000000..c2da7c4
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/extensions/compactnotation/CompactData.java
@@ -0,0 +1,48 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.extensions.compactnotation;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class CompactData {
+ private String prefix;
+ private List<String> arguments = new ArrayList<String>();
+ private Map<String, String> properties = new HashMap<String, String>();
+
+ public CompactData(String prefix) {
+ this.prefix = prefix;
+ }
+
+ public String getPrefix() {
+ return prefix;
+ }
+
+ public Map<String, String> getProperties() {
+ return properties;
+ }
+
+ public List<String> getArguments() {
+ return arguments;
+ }
+
+ @Override
+ public String toString() {
+ return "CompactData: " + prefix + " " + properties;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/org/yaml/snakeyaml/extensions/compactnotation/PackageCompactConstructor.java b/src/main/java/org/yaml/snakeyaml/extensions/compactnotation/PackageCompactConstructor.java
new file mode 100644
index 0000000..e58c3ad
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/extensions/compactnotation/PackageCompactConstructor.java
@@ -0,0 +1,37 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.extensions.compactnotation;
+
+public class PackageCompactConstructor extends CompactConstructor {
+ private String packageName;
+
+ public PackageCompactConstructor(String packageName) {
+ this.packageName = packageName;
+ }
+
+ @Override
+ protected Class<?> getClassForName(String name) throws ClassNotFoundException {
+ if (name.indexOf('.') < 0) {
+ try {
+ Class<?> clazz = Class.forName(packageName + "." + name);
+ return clazz;
+ } catch (ClassNotFoundException e) {
+ // use super implementation
+ }
+ }
+ return super.getClassForName(name);
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/external/biz/base64Coder/Base64Coder.java b/src/main/java/org/yaml/snakeyaml/external/biz/base64Coder/Base64Coder.java
new file mode 100644
index 0000000..65923b6
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/external/biz/base64Coder/Base64Coder.java
@@ -0,0 +1,305 @@
+// Copyright 2003-2010 Christian d'Heureuse, Inventec Informatik AG, Zurich, Switzerland
+// www.source-code.biz, www.inventec.ch/chdh
+//
+// This module is multi-licensed and may be used under the terms
+// of any of the following licenses:
+//
+// EPL, Eclipse Public License, V1.0 or later, http://www.eclipse.org/legal
+// LGPL, GNU Lesser General Public License, V2.1 or later, http://www.gnu.org/licenses/lgpl.html
+// GPL, GNU General Public License, V2 or later, http://www.gnu.org/licenses/gpl.html
+// AL, Apache License, V2.0 or later, http://www.apache.org/licenses
+// BSD, BSD License, http://www.opensource.org/licenses/bsd-license.php
+//
+// Please contact the author if you need another license.
+// This module is provided "as is", without warranties of any kind.
+
+package org.yaml.snakeyaml.external.biz.base64Coder;
+
+/**
+ * A Base64 encoder/decoder.
+ *
+ * <p>
+ * This class is used to encode and decode data in Base64 format as described in
+ * RFC 1521.
+ *
+ * <p>
+ * Project home page: <a
+ * href="http://www.source-code.biz/base64coder/java/">www.
+ * source-code.biz/base64coder/java</a><br>
+ * Author: Christian d'Heureuse, Inventec Informatik AG, Zurich, Switzerland<br>
+ * Multi-licensed: EPL / LGPL / GPL / AL / BSD.
+ */
+public class Base64Coder {
+
+ // The line separator string of the operating system.
+ private static final String systemLineSeparator = System.getProperty("line.separator");
+
+ // Mapping table from 6-bit nibbles to Base64 characters.
+ private 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 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 string into Base64 format. No blanks or line breaks are
+ * inserted.
+ *
+ * @param s
+ * A String to be encoded.
+ * @return A String containing the Base64 encoded data.
+ */
+ public static String encodeString(String s) {
+ return new String(encode(s.getBytes()));
+ }
+
+ /**
+ * Encodes a byte array into Base 64 format and breaks the output into lines
+ * of 76 characters. This method is compatible with
+ * <code>sun.misc.BASE64Encoder.encodeBuffer(byte[])</code>.
+ *
+ * @param in
+ * An array containing the data bytes to be encoded.
+ * @return A String containing the Base64 encoded data, broken into lines.
+ */
+ public static String encodeLines(byte[] in) {
+ return encodeLines(in, 0, in.length, 76, systemLineSeparator);
+ }
+
+ /**
+ * Encodes a byte array into Base 64 format and breaks the output into
+ * lines.
+ *
+ * @param in
+ * An array containing the data bytes to be encoded.
+ * @param iOff
+ * Offset of the first byte in <code>in</code> to be processed.
+ * @param iLen
+ * Number of bytes to be processed in <code>in</code>, starting
+ * at <code>iOff</code>.
+ * @param lineLen
+ * Line length for the output data. Should be a multiple of 4.
+ * @param lineSeparator
+ * The line separator to be used to separate the output lines.
+ * @return A String containing the Base64 encoded data, broken into lines.
+ */
+ public static String encodeLines(byte[] in, int iOff, int iLen, int lineLen,
+ String lineSeparator) {
+ int blockLen = (lineLen * 3) / 4;
+ if (blockLen <= 0)
+ throw new IllegalArgumentException();
+ int lines = (iLen + blockLen - 1) / blockLen;
+ int bufLen = ((iLen + 2) / 3) * 4 + lines * lineSeparator.length();
+ StringBuilder buf = new StringBuilder(bufLen);
+ int ip = 0;
+ while (ip < iLen) {
+ int l = Math.min(iLen - ip, blockLen);
+ buf.append(encode(in, iOff + ip, l));
+ buf.append(lineSeparator);
+ ip += l;
+ }
+ return buf.toString();
+ }
+
+ /**
+ * Encodes a byte array into Base64 format. No blanks or line breaks are
+ * inserted in the output.
+ *
+ * @param in
+ * An array containing the data bytes to be encoded.
+ * @return A character array containing the Base64 encoded data.
+ */
+ public static char[] encode(byte[] in) {
+ return encode(in, 0, in.length);
+ }
+
+ /**
+ * Encodes a byte array into Base64 format. No blanks or line breaks are
+ * inserted in the output.
+ *
+ * @param in
+ * An array containing the data bytes to be encoded.
+ * @param iLen
+ * Number of bytes to process in <code>in</code>.
+ * @return A character array containing the Base64 encoded data.
+ */
+ public static char[] encode(byte[] in, int iLen) {
+ return encode(in, 0, iLen);
+ }
+
+ /**
+ * Encodes a byte array into Base64 format. No blanks or line breaks are
+ * inserted in the output.
+ *
+ * @param in
+ * An array containing the data bytes to be encoded.
+ * @param iOff
+ * Offset of the first byte in <code>in</code> to be processed.
+ * @param iLen
+ * Number of bytes to process in <code>in</code>, starting at
+ * <code>iOff</code>.
+ * @return A character array containing the Base64 encoded data.
+ */
+ public static char[] encode(byte[] in, int iOff, int iLen) {
+ 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 = iOff;
+ int iEnd = iOff + iLen;
+ int op = 0;
+ while (ip < iEnd) {
+ int i0 = in[ip++] & 0xff;
+ int i1 = ip < iEnd ? in[ip++] & 0xff : 0;
+ int i2 = ip < iEnd ? 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 a string from Base64 format. No blanks or line breaks are allowed
+ * within the Base64 encoded input data.
+ *
+ * @param s
+ * A Base64 String to be decoded.
+ * @return A String containing the decoded data.
+ * @throws IllegalArgumentException
+ * If the input is not valid Base64 encoded data.
+ */
+ public static String decodeString(String s) {
+ return new String(decode(s));
+ }
+
+ /**
+ * Decodes a byte array from Base64 format and ignores line separators, tabs
+ * and blanks. CR, LF, Tab and Space characters are ignored in the input
+ * data. This method is compatible with
+ * <code>sun.misc.BASE64Decoder.decodeBuffer(String)</code>.
+ *
+ * @param s
+ * A Base64 String to be decoded.
+ * @return An array containing the decoded data bytes.
+ * @throws IllegalArgumentException
+ * If the input is not valid Base64 encoded data.
+ */
+ public static byte[] decodeLines(String s) {
+ char[] buf = new char[s.length()];
+ int p = 0;
+ for (int ip = 0; ip < s.length(); ip++) {
+ char c = s.charAt(ip);
+ if (c != ' ' && c != '\r' && c != '\n' && c != '\t')
+ buf[p++] = c;
+ }
+ return decode(buf, 0, p);
+ }
+
+ /**
+ * Decodes a byte array from Base64 format. No blanks or line breaks are
+ * allowed within the Base64 encoded input data.
+ *
+ * @param s
+ * A Base64 String to be decoded.
+ * @return An array containing the decoded data bytes.
+ * @throws IllegalArgumentException
+ * If the input is not valid Base64 encoded data.
+ */
+ public static byte[] decode(String s) {
+ return decode(s.toCharArray());
+ }
+
+ /**
+ * Decodes a byte array from Base64 format. No blanks or line breaks are
+ * allowed within the Base64 encoded input 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) {
+ return decode(in, 0, in.length);
+ }
+
+ /**
+ * Decodes a byte array from Base64 format. No blanks or line breaks are
+ * allowed within the Base64 encoded input data.
+ *
+ * @param in
+ * A character array containing the Base64 encoded data.
+ * @param iOff
+ * Offset of the first character in <code>in</code> to be
+ * processed.
+ * @param iLen
+ * Number of characters to process in <code>in</code>, starting
+ * at <code>iOff</code>.
+ * @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 iOff, int iLen) {
+ if (iLen % 4 != 0)
+ throw new IllegalArgumentException(
+ "Length of Base64 encoded input string is not a multiple of 4.");
+ while (iLen > 0 && in[iOff + iLen - 1] == '=')
+ iLen--;
+ int oLen = (iLen * 3) / 4;
+ byte[] out = new byte[oLen];
+ int ip = iOff;
+ int iEnd = iOff + iLen;
+ int op = 0;
+ while (ip < iEnd) {
+ int i0 = in[ip++];
+ int i1 = in[ip++];
+ int i2 = ip < iEnd ? in[ip++] : 'A';
+ int i3 = ip < iEnd ? in[ip++] : 'A';
+ if (i0 > 127 || i1 > 127 || i2 > 127 || i3 > 127)
+ throw new IllegalArgumentException("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 IllegalArgumentException("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;
+ }
+
+ // Dummy constructor.
+ private Base64Coder() {
+ }
+
+} // end class Base64Coder
diff --git a/src/main/java/org/yaml/snakeyaml/external/com/google/gdata/util/common/base/Escaper.java b/src/main/java/org/yaml/snakeyaml/external/com/google/gdata/util/common/base/Escaper.java
new file mode 100644
index 0000000..c26e3cb
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/external/com/google/gdata/util/common/base/Escaper.java
@@ -0,0 +1,97 @@
+/* Copyright (c) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.yaml.snakeyaml.external.com.google.gdata.util.common.base;
+
+/**
+ * An object that converts literal text into a format safe for inclusion in a
+ * particular context (such as an XML document). Typically (but not always), the
+ * inverse process of "unescaping" the text is performed automatically by the
+ * relevant parser.
+ *
+ * <p>
+ * For example, an XML escaper would convert the literal string
+ * {@code "Foo<Bar>"} into {@code "Foo<Bar>"} to prevent {@code "<Bar>"}
+ * from being confused with an XML tag. When the resulting XML document is
+ * parsed, the parser API will return this text as the original literal string
+ * {@code "Foo<Bar>"}.
+ *
+ * <p>
+ * An {@code Escaper} instance is required to be stateless, and safe when used
+ * concurrently by multiple threads.
+ *
+ * <p>
+ * Several popular escapers are defined as constants in the class
+ * {@link CharEscapers}. To create your own escapers, use
+ * {@link CharEscaperBuilder}, or extend {@link CharEscaper} or
+ * {@code UnicodeEscaper}.
+ *
+ *
+ */
+public interface Escaper {
+ /**
+ * Returns the escaped form of a given literal string.
+ *
+ * <p>
+ * Note that this method may treat input characters differently depending on
+ * the specific escaper implementation.
+ * <ul>
+ * <li>{@link UnicodeEscaper} handles <a
+ * href="http://en.wikipedia.org/wiki/UTF-16">UTF-16</a> correctly,
+ * including surrogate character pairs. If the input is badly formed the
+ * escaper should throw {@link IllegalArgumentException}.
+ * <li>{@link CharEscaper} handles Java characters independently and does
+ * not verify the input for well formed characters. A CharEscaper should not
+ * be used in situations where input is not guaranteed to be restricted to
+ * the Basic Multilingual Plane (BMP).
+ * </ul>
+ *
+ * @param string
+ * the literal string to be escaped
+ * @return the escaped form of {@code string}
+ * @throws NullPointerException
+ * if {@code string} is null
+ * @throws IllegalArgumentException
+ * if {@code string} contains badly formed UTF-16 or cannot be
+ * escaped for any other reason
+ */
+ public String escape(String string);
+
+ /**
+ * Returns an {@code Appendable} instance which automatically escapes all
+ * text appended to it before passing the resulting text to an underlying
+ * {@code Appendable}.
+ *
+ * <p>
+ * Note that this method may treat input characters differently depending on
+ * the specific escaper implementation.
+ * <ul>
+ * <li>{@link UnicodeEscaper} handles <a
+ * href="http://en.wikipedia.org/wiki/UTF-16">UTF-16</a> correctly,
+ * including surrogate character pairs. If the input is badly formed the
+ * escaper should throw {@link IllegalArgumentException}.
+ * <li>{@link CharEscaper} handles Java characters independently and does
+ * not verify the input for well formed characters. A CharEscaper should not
+ * be used in situations where input is not guaranteed to be restricted to
+ * the Basic Multilingual Plane (BMP).
+ * </ul>
+ *
+ * @param out
+ * the underlying {@code Appendable} to append escaped output to
+ * @return an {@code Appendable} which passes text to {@code out} after
+ * escaping it.
+ */
+ public Appendable escape(Appendable out);
+}
diff --git a/src/main/java/org/yaml/snakeyaml/external/com/google/gdata/util/common/base/PercentEscaper.java b/src/main/java/org/yaml/snakeyaml/external/com/google/gdata/util/common/base/PercentEscaper.java
new file mode 100644
index 0000000..5e2f902
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/external/com/google/gdata/util/common/base/PercentEscaper.java
@@ -0,0 +1,281 @@
+/* Copyright (c) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.yaml.snakeyaml.external.com.google.gdata.util.common.base;
+
+/**
+ * A {@code UnicodeEscaper} that escapes some set of Java characters using the
+ * URI percent encoding scheme. The set of safe characters (those which remain
+ * unescaped) can be specified on construction.
+ *
+ * <p>
+ * For details on escaping URIs for use in web pages, see section 2.4 of <a
+ * href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986</a>.
+ *
+ * <p>
+ * In most cases this class should not need to be used directly. If you have no
+ * special requirements for escaping your URIs, you should use either
+ * {@link CharEscapers#uriEscaper()} or {@link CharEscapers#uriEscaper(boolean)}.
+ *
+ * <p>
+ * When encoding a String, the following rules apply:
+ * <ul>
+ * <li>The alphanumeric characters "a" through "z", "A" through "Z" and "0"
+ * through "9" remain the same.
+ * <li>Any additionally specified safe characters remain the same.
+ * <li>If {@code plusForSpace} was specified, the space character " " is
+ * converted into a plus sign "+".
+ * <li>All other characters are converted into one or more bytes using UTF-8
+ * encoding and each byte is then represented by the 3-character string "%XY",
+ * where "XY" is the two-digit, uppercase, hexadecimal representation of the
+ * byte value.
+ * </ul>
+ *
+ * <p>
+ * RFC 2396 specifies the set of unreserved characters as "-", "_", ".", "!",
+ * "~", "*", "'", "(" and ")". It goes on to state:
+ *
+ * <p>
+ * <i>Unreserved characters can be escaped without changing the semantics of the
+ * URI, but this should not be done unless the URI is being used in a context
+ * that does not allow the unescaped character to appear.</i>
+ *
+ * <p>
+ * For performance reasons the only currently supported character encoding of
+ * this class is UTF-8.
+ *
+ * <p>
+ * <b>Note</b>: This escaper produces uppercase hexidecimal sequences. From <a
+ * href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986</a>:<br>
+ * <i>"URI producers and normalizers should use uppercase hexadecimal digits for
+ * all percent-encodings."</i>
+ *
+ *
+ */
+public class PercentEscaper extends UnicodeEscaper {
+ /**
+ * A string of safe characters that mimics the behavior of
+ * {@link java.net.URLEncoder}.
+ *
+ */
+ public static final String SAFECHARS_URLENCODER = "-_.*";
+
+ /**
+ * A string of characters that do not need to be encoded when used in URI
+ * path segments, as specified in RFC 3986. Note that some of these
+ * characters do need to be escaped when used in other parts of the URI.
+ */
+ public static final String SAFEPATHCHARS_URLENCODER = "-_.!~*'()@:$&,;=";
+
+ /**
+ * A string of characters that do not need to be encoded when used in URI
+ * query strings, as specified in RFC 3986. Note that some of these
+ * characters do need to be escaped when used in other parts of the URI.
+ */
+ public static final String SAFEQUERYSTRINGCHARS_URLENCODER = "-_.!~*'()@:$,;/?:";
+
+ // In some uri escapers spaces are escaped to '+'
+ private static final char[] URI_ESCAPED_SPACE = { '+' };
+
+ private static final char[] UPPER_HEX_DIGITS = "0123456789ABCDEF".toCharArray();
+
+ /**
+ * If true we should convert space to the {@code +} character.
+ */
+ private final boolean plusForSpace;
+
+ /**
+ * An array of flags where for any {@code char c} if {@code safeOctets[c]}
+ * is true then {@code c} should remain unmodified in the output. If
+ * {@code c > safeOctets.length} then it should be escaped.
+ */
+ private final boolean[] safeOctets;
+
+ /**
+ * Constructs a URI escaper with the specified safe characters and optional
+ * handling of the space character.
+ *
+ * @param safeChars
+ * a non null string specifying additional safe characters for
+ * this escaper (the ranges 0..9, a..z and A..Z are always safe
+ * and should not be specified here)
+ * @param plusForSpace
+ * true if ASCII space should be escaped to {@code +} rather than
+ * {@code %20}
+ * @throws IllegalArgumentException
+ * if any of the parameters were invalid
+ */
+ public PercentEscaper(String safeChars, boolean plusForSpace) {
+ // Avoid any misunderstandings about the behavior of this escaper
+ if (safeChars.matches(".*[0-9A-Za-z].*")) {
+ throw new IllegalArgumentException(
+ "Alphanumeric characters are always 'safe' and should not be "
+ + "explicitly specified");
+ }
+ // Avoid ambiguous parameters. Safe characters are never modified so if
+ // space is a safe character then setting plusForSpace is meaningless.
+ if (plusForSpace && safeChars.contains(" ")) {
+ throw new IllegalArgumentException(
+ "plusForSpace cannot be specified when space is a 'safe' character");
+ }
+ if (safeChars.contains("%")) {
+ throw new IllegalArgumentException("The '%' character cannot be specified as 'safe'");
+ }
+ this.plusForSpace = plusForSpace;
+ this.safeOctets = createSafeOctets(safeChars);
+ }
+
+ /**
+ * Creates a boolean[] with entries corresponding to the character values
+ * for 0-9, A-Z, a-z and those specified in safeChars set to true. The array
+ * is as small as is required to hold the given character information.
+ */
+ private static boolean[] createSafeOctets(String safeChars) {
+ int maxChar = 'z';
+ char[] safeCharArray = safeChars.toCharArray();
+ for (char c : safeCharArray) {
+ maxChar = Math.max(c, maxChar);
+ }
+ boolean[] octets = new boolean[maxChar + 1];
+ for (int c = '0'; c <= '9'; c++) {
+ octets[c] = true;
+ }
+ for (int c = 'A'; c <= 'Z'; c++) {
+ octets[c] = true;
+ }
+ for (int c = 'a'; c <= 'z'; c++) {
+ octets[c] = true;
+ }
+ for (char c : safeCharArray) {
+ octets[c] = true;
+ }
+ return octets;
+ }
+
+ /*
+ * Overridden for performance. For unescaped strings this improved the
+ * performance of the uri escaper from ~760ns to ~400ns as measured by
+ * {@link CharEscapersBenchmark}.
+ */
+ @Override
+ protected int nextEscapeIndex(CharSequence csq, int index, int end) {
+ for (; index < end; index++) {
+ char c = csq.charAt(index);
+ if (c >= safeOctets.length || !safeOctets[c]) {
+ break;
+ }
+ }
+ return index;
+ }
+
+ /*
+ * Overridden for performance. For unescaped strings this improved the
+ * performance of the uri escaper from ~400ns to ~170ns as measured by
+ * {@link CharEscapersBenchmark}.
+ */
+ @Override
+ public String escape(String s) {
+ int slen = s.length();
+ for (int index = 0; index < slen; index++) {
+ char c = s.charAt(index);
+ if (c >= safeOctets.length || !safeOctets[c]) {
+ return escapeSlow(s, index);
+ }
+ }
+ return s;
+ }
+
+ /**
+ * Escapes the given Unicode code point in UTF-8.
+ */
+ @Override
+ protected char[] escape(int cp) {
+ // We should never get negative values here but if we do it will throw
+ // an
+ // IndexOutOfBoundsException, so at least it will get spotted.
+ if (cp < safeOctets.length && safeOctets[cp]) {
+ return null;
+ } else if (cp == ' ' && plusForSpace) {
+ return URI_ESCAPED_SPACE;
+ } else if (cp <= 0x7F) {
+ // Single byte UTF-8 characters
+ // Start with "%--" and fill in the blanks
+ char[] dest = new char[3];
+ dest[0] = '%';
+ dest[2] = UPPER_HEX_DIGITS[cp & 0xF];
+ dest[1] = UPPER_HEX_DIGITS[cp >>> 4];
+ return dest;
+ } else if (cp <= 0x7ff) {
+ // Two byte UTF-8 characters [cp >= 0x80 && cp <= 0x7ff]
+ // Start with "%--%--" and fill in the blanks
+ char[] dest = new char[6];
+ dest[0] = '%';
+ dest[3] = '%';
+ dest[5] = UPPER_HEX_DIGITS[cp & 0xF];
+ cp >>>= 4;
+ dest[4] = UPPER_HEX_DIGITS[0x8 | (cp & 0x3)];
+ cp >>>= 2;
+ dest[2] = UPPER_HEX_DIGITS[cp & 0xF];
+ cp >>>= 4;
+ dest[1] = UPPER_HEX_DIGITS[0xC | cp];
+ return dest;
+ } else if (cp <= 0xffff) {
+ // Three byte UTF-8 characters [cp >= 0x800 && cp <= 0xffff]
+ // Start with "%E-%--%--" and fill in the blanks
+ char[] dest = new char[9];
+ dest[0] = '%';
+ dest[1] = 'E';
+ dest[3] = '%';
+ dest[6] = '%';
+ dest[8] = UPPER_HEX_DIGITS[cp & 0xF];
+ cp >>>= 4;
+ dest[7] = UPPER_HEX_DIGITS[0x8 | (cp & 0x3)];
+ cp >>>= 2;
+ dest[5] = UPPER_HEX_DIGITS[cp & 0xF];
+ cp >>>= 4;
+ dest[4] = UPPER_HEX_DIGITS[0x8 | (cp & 0x3)];
+ cp >>>= 2;
+ dest[2] = UPPER_HEX_DIGITS[cp];
+ return dest;
+ } else if (cp <= 0x10ffff) {
+ char[] dest = new char[12];
+ // Four byte UTF-8 characters [cp >= 0xffff && cp <= 0x10ffff]
+ // Start with "%F-%--%--%--" and fill in the blanks
+ dest[0] = '%';
+ dest[1] = 'F';
+ dest[3] = '%';
+ dest[6] = '%';
+ dest[9] = '%';
+ dest[11] = UPPER_HEX_DIGITS[cp & 0xF];
+ cp >>>= 4;
+ dest[10] = UPPER_HEX_DIGITS[0x8 | (cp & 0x3)];
+ cp >>>= 2;
+ dest[8] = UPPER_HEX_DIGITS[cp & 0xF];
+ cp >>>= 4;
+ dest[7] = UPPER_HEX_DIGITS[0x8 | (cp & 0x3)];
+ cp >>>= 2;
+ dest[5] = UPPER_HEX_DIGITS[cp & 0xF];
+ cp >>>= 4;
+ dest[4] = UPPER_HEX_DIGITS[0x8 | (cp & 0x3)];
+ cp >>>= 2;
+ dest[2] = UPPER_HEX_DIGITS[cp & 0x7];
+ return dest;
+ } else {
+ // If this ever happens it is due to bug in UnicodeEscaper, not bad
+ // input.
+ throw new IllegalArgumentException("Invalid unicode character value " + cp);
+ }
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/external/com/google/gdata/util/common/base/UnicodeEscaper.java b/src/main/java/org/yaml/snakeyaml/external/com/google/gdata/util/common/base/UnicodeEscaper.java
new file mode 100644
index 0000000..5403185
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/external/com/google/gdata/util/common/base/UnicodeEscaper.java
@@ -0,0 +1,506 @@
+/* Copyright (c) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.yaml.snakeyaml.external.com.google.gdata.util.common.base;
+
+import java.io.IOException;
+
+/**
+ * An {@link Escaper} that converts literal text into a format safe for
+ * inclusion in a particular context (such as an XML document). Typically (but
+ * not always), the inverse process of "unescaping" the text is performed
+ * automatically by the relevant parser.
+ *
+ * <p>
+ * For example, an XML escaper would convert the literal string
+ * {@code "Foo<Bar>"} into {@code "Foo<Bar>"} to prevent {@code "<Bar>"}
+ * from being confused with an XML tag. When the resulting XML document is
+ * parsed, the parser API will return this text as the original literal string
+ * {@code "Foo<Bar>"}.
+ *
+ * <p>
+ * <b>Note:</b> This class is similar to {@link CharEscaper} but with one very
+ * important difference. A CharEscaper can only process Java <a
+ * href="http://en.wikipedia.org/wiki/UTF-16">UTF16</a> characters in isolation
+ * and may not cope when it encounters surrogate pairs. This class facilitates
+ * the correct escaping of all Unicode characters.
+ *
+ * <p>
+ * As there are important reasons, including potential security issues, to
+ * handle Unicode correctly if you are considering implementing a new escaper
+ * you should favor using UnicodeEscaper wherever possible.
+ *
+ * <p>
+ * A {@code UnicodeEscaper} instance is required to be stateless, and safe when
+ * used concurrently by multiple threads.
+ *
+ * <p>
+ * Several popular escapers are defined as constants in the class
+ * {@link CharEscapers}. To create your own escapers extend this class and
+ * implement the {@link #escape(int)} method.
+ *
+ *
+ */
+public abstract class UnicodeEscaper implements Escaper {
+ /** The amount of padding (chars) to use when growing the escape buffer. */
+ private static final int DEST_PAD = 32;
+
+ /**
+ * Returns the escaped form of the given Unicode code point, or {@code null}
+ * if this code point does not need to be escaped. When called as part of an
+ * escaping operation, the given code point is guaranteed to be in the range
+ * {@code 0 <= cp <= Character#MAX_CODE_POINT}.
+ *
+ * <p>
+ * If an empty array is returned, this effectively strips the input
+ * character from the resulting text.
+ *
+ * <p>
+ * If the character does not need to be escaped, this method should return
+ * {@code null}, rather than an array containing the character
+ * representation of the code point. This enables the escaping algorithm to
+ * perform more efficiently.
+ *
+ * <p>
+ * If the implementation of this method cannot correctly handle a particular
+ * code point then it should either throw an appropriate runtime exception
+ * or return a suitable replacement character. It must never silently
+ * discard invalid input as this may constitute a security risk.
+ *
+ * @param cp
+ * the Unicode code point to escape if necessary
+ * @return the replacement characters, or {@code null} if no escaping was
+ * needed
+ */
+ protected abstract char[] escape(int cp);
+
+ /**
+ * Scans a sub-sequence of characters from a given {@link CharSequence},
+ * returning the index of the next character that requires escaping.
+ *
+ * <p>
+ * <b>Note:</b> When implementing an escaper, it is a good idea to override
+ * this method for efficiency. The base class implementation determines
+ * successive Unicode code points and invokes {@link #escape(int)} for each
+ * of them. If the semantics of your escaper are such that code points in
+ * the supplementary range are either all escaped or all unescaped, this
+ * method can be implemented more efficiently using
+ * {@link CharSequence#charAt(int)}.
+ *
+ * <p>
+ * Note however that if your escaper does not escape characters in the
+ * supplementary range, you should either continue to validate the
+ * correctness of any surrogate characters encountered or provide a clear
+ * warning to users that your escaper does not validate its input.
+ *
+ * <p>
+ * See {@link PercentEscaper} for an example.
+ *
+ * @param csq
+ * a sequence of characters
+ * @param start
+ * the index of the first character to be scanned
+ * @param end
+ * the index immediately after the last character to be scanned
+ * @throws IllegalArgumentException
+ * if the scanned sub-sequence of {@code csq} contains invalid
+ * surrogate pairs
+ */
+ protected int nextEscapeIndex(CharSequence csq, int start, int end) {
+ int index = start;
+ while (index < end) {
+ int cp = codePointAt(csq, index, end);
+ if (cp < 0 || escape(cp) != null) {
+ break;
+ }
+ index += Character.isSupplementaryCodePoint(cp) ? 2 : 1;
+ }
+ return index;
+ }
+
+ /**
+ * Returns the escaped form of a given literal string.
+ *
+ * <p>
+ * If you are escaping input in arbitrary successive chunks, then it is not
+ * generally safe to use this method. If an input string ends with an
+ * unmatched high surrogate character, then this method will throw
+ * {@link IllegalArgumentException}. You should either ensure your input is
+ * valid <a href="http://en.wikipedia.org/wiki/UTF-16">UTF-16</a> before
+ * calling this method or use an escaped {@link Appendable} (as returned by
+ * {@link #escape(Appendable)}) which can cope with arbitrarily split input.
+ *
+ * <p>
+ * <b>Note:</b> When implementing an escaper it is a good idea to override
+ * this method for efficiency by inlining the implementation of
+ * {@link #nextEscapeIndex(CharSequence, int, int)} directly. Doing this for
+ * {@link PercentEscaper} more than doubled the performance for unescaped
+ * strings (as measured by {@link CharEscapersBenchmark}).
+ *
+ * @param string
+ * the literal string to be escaped
+ * @return the escaped form of {@code string}
+ * @throws NullPointerException
+ * if {@code string} is null
+ * @throws IllegalArgumentException
+ * if invalid surrogate characters are encountered
+ */
+ public String escape(String string) {
+ int end = string.length();
+ int index = nextEscapeIndex(string, 0, end);
+ return index == end ? string : escapeSlow(string, index);
+ }
+
+ /**
+ * Returns the escaped form of a given literal string, starting at the given
+ * index. This method is called by the {@link #escape(String)} method when
+ * it discovers that escaping is required. It is protected to allow
+ * subclasses to override the fastpath escaping function to inline their
+ * escaping test. See {@link CharEscaperBuilder} for an example usage.
+ *
+ * <p>
+ * This method is not reentrant and may only be invoked by the top level
+ * {@link #escape(String)} method.
+ *
+ * @param s
+ * the literal string to be escaped
+ * @param index
+ * the index to start escaping from
+ * @return the escaped form of {@code string}
+ * @throws NullPointerException
+ * if {@code string} is null
+ * @throws IllegalArgumentException
+ * if invalid surrogate characters are encountered
+ */
+ protected final String escapeSlow(String s, int index) {
+ int end = s.length();
+
+ // Get a destination buffer and setup some loop variables.
+ char[] dest = DEST_TL.get();
+ int destIndex = 0;
+ int unescapedChunkStart = 0;
+
+ while (index < end) {
+ int cp = codePointAt(s, index, end);
+ if (cp < 0) {
+ throw new IllegalArgumentException("Trailing high surrogate at end of input");
+ }
+ char[] escaped = escape(cp);
+ if (escaped != null) {
+ int charsSkipped = index - unescapedChunkStart;
+
+ // This is the size needed to add the replacement, not the full
+ // size needed by the string. We only regrow when we absolutely
+ // must.
+ int sizeNeeded = destIndex + charsSkipped + escaped.length;
+ if (dest.length < sizeNeeded) {
+ int destLength = sizeNeeded + (end - index) + DEST_PAD;
+ dest = growBuffer(dest, destIndex, destLength);
+ }
+ // If we have skipped any characters, we need to copy them now.
+ if (charsSkipped > 0) {
+ s.getChars(unescapedChunkStart, index, dest, destIndex);
+ destIndex += charsSkipped;
+ }
+ if (escaped.length > 0) {
+ System.arraycopy(escaped, 0, dest, destIndex, escaped.length);
+ destIndex += escaped.length;
+ }
+ }
+ unescapedChunkStart = index + (Character.isSupplementaryCodePoint(cp) ? 2 : 1);
+ index = nextEscapeIndex(s, unescapedChunkStart, end);
+ }
+
+ // Process trailing unescaped characters - no need to account for
+ // escaped
+ // length or padding the allocation.
+ int charsSkipped = end - unescapedChunkStart;
+ if (charsSkipped > 0) {
+ int endIndex = destIndex + charsSkipped;
+ if (dest.length < endIndex) {
+ dest = growBuffer(dest, destIndex, endIndex);
+ }
+ s.getChars(unescapedChunkStart, end, dest, destIndex);
+ destIndex = endIndex;
+ }
+ return new String(dest, 0, destIndex);
+ }
+
+ /**
+ * Returns an {@code Appendable} instance which automatically escapes all
+ * text appended to it before passing the resulting text to an underlying
+ * {@code Appendable}.
+ *
+ * <p>
+ * Unlike {@link #escape(String)} it is permitted to append arbitrarily
+ * split input to this Appendable, including input that is split over a
+ * surrogate pair. In this case the pending high surrogate character will
+ * not be processed until the corresponding low surrogate is appended. This
+ * means that a trailing high surrogate character at the end of the input
+ * cannot be detected and will be silently ignored. This is unavoidable
+ * since the Appendable interface has no {@code close()} method, and it is
+ * impossible to determine when the last characters have been appended.
+ *
+ * <p>
+ * The methods of the returned object will propagate any exceptions thrown
+ * by the underlying {@code Appendable}.
+ *
+ * <p>
+ * For well formed <a href="http://en.wikipedia.org/wiki/UTF-16">UTF-16</a>
+ * the escaping behavior is identical to that of {@link #escape(String)} and
+ * the following code is equivalent to (but much slower than)
+ * {@code escaper.escape(string)}:
+ *
+ * <pre>
+ * {
+ * @code
+ * StringBuilder sb = new StringBuilder();
+ * escaper.escape(sb).append(string);
+ * return sb.toString();
+ * }
+ * </pre>
+ *
+ * @param out
+ * the underlying {@code Appendable} to append escaped output to
+ * @return an {@code Appendable} which passes text to {@code out} after
+ * escaping it
+ * @throws NullPointerException
+ * if {@code out} is null
+ * @throws IllegalArgumentException
+ * if invalid surrogate characters are encountered
+ *
+ */
+ public Appendable escape(final Appendable out) {
+ assert out != null;
+
+ return new Appendable() {
+ int pendingHighSurrogate = -1;
+ char[] decodedChars = new char[2];
+
+ public Appendable append(CharSequence csq) throws IOException {
+ return append(csq, 0, csq.length());
+ }
+
+ public Appendable append(CharSequence csq, int start, int end) throws IOException {
+ int index = start;
+ if (index < end) {
+ // This is a little subtle: index must never reference the
+ // middle of a
+ // surrogate pair but unescapedChunkStart can. The first
+ // time we enter
+ // the loop below it is possible that index !=
+ // unescapedChunkStart.
+ int unescapedChunkStart = index;
+ if (pendingHighSurrogate != -1) {
+ // Our last append operation ended halfway through a
+ // surrogate pair
+ // so we have to do some extra work first.
+ char c = csq.charAt(index++);
+ if (!Character.isLowSurrogate(c)) {
+ throw new IllegalArgumentException(
+ "Expected low surrogate character but got " + c);
+ }
+ char[] escaped = escape(Character.toCodePoint((char) pendingHighSurrogate,
+ c));
+ if (escaped != null) {
+ // Emit the escaped character and adjust
+ // unescapedChunkStart to
+ // skip the low surrogate we have consumed.
+ outputChars(escaped, escaped.length);
+ unescapedChunkStart += 1;
+ } else {
+ // Emit pending high surrogate (unescaped) but do
+ // not modify
+ // unescapedChunkStart as we must still emit the low
+ // surrogate.
+ out.append((char) pendingHighSurrogate);
+ }
+ pendingHighSurrogate = -1;
+ }
+ while (true) {
+ // Find and append the next subsequence of unescaped
+ // characters.
+ index = nextEscapeIndex(csq, index, end);
+ if (index > unescapedChunkStart) {
+ out.append(csq, unescapedChunkStart, index);
+ }
+ if (index == end) {
+ break;
+ }
+ // If we are not finished, calculate the next code
+ // point.
+ int cp = codePointAt(csq, index, end);
+ if (cp < 0) {
+ // Our sequence ended half way through a surrogate
+ // pair so just
+ // record the state and exit.
+ pendingHighSurrogate = -cp;
+ break;
+ }
+ // Escape the code point and output the characters.
+ char[] escaped = escape(cp);
+ if (escaped != null) {
+ outputChars(escaped, escaped.length);
+ } else {
+ // This shouldn't really happen if nextEscapeIndex
+ // is correct but
+ // we should cope with false positives.
+ int len = Character.toChars(cp, decodedChars, 0);
+ outputChars(decodedChars, len);
+ }
+ // Update our index past the escaped character and
+ // continue.
+ index += (Character.isSupplementaryCodePoint(cp) ? 2 : 1);
+ unescapedChunkStart = index;
+ }
+ }
+ return this;
+ }
+
+ public Appendable append(char c) throws IOException {
+ if (pendingHighSurrogate != -1) {
+ // Our last append operation ended halfway through a
+ // surrogate pair
+ // so we have to do some extra work first.
+ if (!Character.isLowSurrogate(c)) {
+ throw new IllegalArgumentException(
+ "Expected low surrogate character but got '" + c + "' with value "
+ + (int) c);
+ }
+ char[] escaped = escape(Character.toCodePoint((char) pendingHighSurrogate, c));
+ if (escaped != null) {
+ outputChars(escaped, escaped.length);
+ } else {
+ out.append((char) pendingHighSurrogate);
+ out.append(c);
+ }
+ pendingHighSurrogate = -1;
+ } else if (Character.isHighSurrogate(c)) {
+ // This is the start of a (split) surrogate pair.
+ pendingHighSurrogate = c;
+ } else {
+ if (Character.isLowSurrogate(c)) {
+ throw new IllegalArgumentException("Unexpected low surrogate character '"
+ + c + "' with value " + (int) c);
+ }
+ // This is a normal (non surrogate) char.
+ char[] escaped = escape(c);
+ if (escaped != null) {
+ outputChars(escaped, escaped.length);
+ } else {
+ out.append(c);
+ }
+ }
+ return this;
+ }
+
+ private void outputChars(char[] chars, int len) throws IOException {
+ for (int n = 0; n < len; n++) {
+ out.append(chars[n]);
+ }
+ }
+ };
+ }
+
+ /**
+ * Returns the Unicode code point of the character at the given index.
+ *
+ * <p>
+ * Unlike {@link Character#codePointAt(CharSequence, int)} or
+ * {@link String#codePointAt(int)} this method will never fail silently when
+ * encountering an invalid surrogate pair.
+ *
+ * <p>
+ * The behaviour of this method is as follows:
+ * <ol>
+ * <li>If {@code index >= end}, {@link IndexOutOfBoundsException} is thrown.
+ * <li><b>If the character at the specified index is not a surrogate, it is
+ * returned.</b>
+ * <li>If the first character was a high surrogate value, then an attempt is
+ * made to read the next character.
+ * <ol>
+ * <li><b>If the end of the sequence was reached, the negated value of the
+ * trailing high surrogate is returned.</b>
+ * <li><b>If the next character was a valid low surrogate, the code point
+ * value of the high/low surrogate pair is returned.</b>
+ * <li>If the next character was not a low surrogate value, then
+ * {@link IllegalArgumentException} is thrown.
+ * </ol>
+ * <li>If the first character was a low surrogate value,
+ * {@link IllegalArgumentException} is thrown.
+ * </ol>
+ *
+ * @param seq
+ * the sequence of characters from which to decode the code point
+ * @param index
+ * the index of the first character to decode
+ * @param end
+ * the index beyond the last valid character to decode
+ * @return the Unicode code point for the given index or the negated value
+ * of the trailing high surrogate character at the end of the
+ * sequence
+ */
+ protected static final int codePointAt(CharSequence seq, int index, int end) {
+ if (index < end) {
+ char c1 = seq.charAt(index++);
+ if (c1 < Character.MIN_HIGH_SURROGATE || c1 > Character.MAX_LOW_SURROGATE) {
+ // Fast path (first test is probably all we need to do)
+ return c1;
+ } else if (c1 <= Character.MAX_HIGH_SURROGATE) {
+ // If the high surrogate was the last character, return its
+ // inverse
+ if (index == end) {
+ return -c1;
+ }
+ // Otherwise look for the low surrogate following it
+ char c2 = seq.charAt(index);
+ if (Character.isLowSurrogate(c2)) {
+ return Character.toCodePoint(c1, c2);
+ }
+ throw new IllegalArgumentException("Expected low surrogate but got char '" + c2
+ + "' with value " + (int) c2 + " at index " + index);
+ } else {
+ throw new IllegalArgumentException("Unexpected low surrogate character '" + c1
+ + "' with value " + (int) c1 + " at index " + (index - 1));
+ }
+ }
+ throw new IndexOutOfBoundsException("Index exceeds specified range");
+ }
+
+ /**
+ * Helper method to grow the character buffer as needed, this only happens
+ * once in a while so it's ok if it's in a method call. If the index passed
+ * in is 0 then no copying will be done.
+ */
+ private static final char[] growBuffer(char[] dest, int index, int size) {
+ char[] copy = new char[size];
+ if (index > 0) {
+ System.arraycopy(dest, 0, copy, 0, index);
+ }
+ return copy;
+ }
+
+ /**
+ * A thread-local destination buffer to keep us from creating new buffers.
+ * The starting size is 1024 characters. If we grow past this we don't put
+ * it back in the threadlocal, we just keep going and grow as needed.
+ */
+ private static final ThreadLocal<char[]> DEST_TL = new ThreadLocal<char[]>() {
+ @Override
+ protected char[] initialValue() {
+ return new char[1024];
+ }
+ };
+}
diff --git a/src/main/java/org/yaml/snakeyaml/introspector/BeanAccess.java b/src/main/java/org/yaml/snakeyaml/introspector/BeanAccess.java
new file mode 100644
index 0000000..696fec7
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/introspector/BeanAccess.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.introspector;
+
+/**
+ * Control instance variables.
+ */
+public enum BeanAccess {
+ /** use JavaBean properties and public fields */
+ DEFAULT,
+
+ /** use all declared fields (including inherited) */
+ FIELD,
+
+ /** reserved */
+ PROPERTY;
+}
\ No newline at end of file
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 0000000..9bc38aa
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/introspector/FieldProperty.java
@@ -0,0 +1,52 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.introspector;
+
+import java.lang.reflect.Field;
+
+import org.yaml.snakeyaml.error.YAMLException;
+
+/**
+ * <p>
+ * A <code>FieldProperty</code> is a <code>Property</code> which is accessed as
+ * a field, without going through accessor methods (setX, getX). The field may
+ * have any scope (public, package, protected, private).
+ * </p>
+ */
+public class FieldProperty extends GenericProperty {
+ private final Field field;
+
+ public FieldProperty(Field field) {
+ super(field.getName(), field.getType(), field.getGenericType());
+ this.field = field;
+ field.setAccessible(true);
+ }
+
+ @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/GenericProperty.java b/src/main/java/org/yaml/snakeyaml/introspector/GenericProperty.java
new file mode 100644
index 0000000..3098160
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/introspector/GenericProperty.java
@@ -0,0 +1,82 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.introspector;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+
+abstract public class GenericProperty extends Property {
+
+ private Type genType;
+
+ public GenericProperty(String name, Class<?> aClass, Type aType) {
+ super(name, aClass);
+ genType = aType;
+ actualClassesChecked = aType == null;
+ }
+
+ private boolean actualClassesChecked;
+ private Class<?>[] actualClasses;
+
+ public Class<?>[] getActualTypeArguments() { // should we synchronize here ?
+ if (!actualClassesChecked) {
+ if (genType instanceof ParameterizedType) {
+ ParameterizedType parameterizedType = (ParameterizedType) genType;
+ Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
+ if (actualTypeArguments.length > 0) {
+ actualClasses = new Class<?>[actualTypeArguments.length];
+ for (int i = 0; i < actualTypeArguments.length; i++) {
+ if (actualTypeArguments[i] instanceof Class<?>) {
+ actualClasses[i] = (Class<?>) actualTypeArguments[i];
+ } else if (actualTypeArguments[i] instanceof ParameterizedType) {
+ actualClasses[i] = (Class<?>) ((ParameterizedType) actualTypeArguments[i])
+ .getRawType();
+ } else if (actualTypeArguments[i] instanceof GenericArrayType) {
+ Type componentType = ((GenericArrayType) actualTypeArguments[i])
+ .getGenericComponentType();
+ if (componentType instanceof Class<?>) {
+ actualClasses[i] = Array.newInstance((Class<?>) componentType, 0)
+ .getClass();
+ } else {
+ actualClasses = null;
+ break;
+ }
+ } else {
+ actualClasses = null;
+ break;
+ }
+ }
+ }
+ } else if (genType instanceof GenericArrayType) {
+ Type componentType = ((GenericArrayType) genType).getGenericComponentType();
+ if (componentType instanceof Class<?>) {
+ actualClasses = new Class<?>[] { (Class<?>) componentType };
+ }
+ } else if (genType instanceof Class<?>) {// XXX this check is only
+ // required for IcedTea6
+ Class<?> classType = (Class<?>) genType;
+ if (classType.isArray()) {
+ actualClasses = new Class<?>[1];
+ actualClasses[0] = getType().getComponentType();
+ }
+ }
+ actualClassesChecked = true;
+ }
+ return actualClasses;
+ }
+}
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 0000000..fc6e00d
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/introspector/MethodProperty.java
@@ -0,0 +1,71 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.introspector;
+
+import java.beans.PropertyDescriptor;
+
+import org.yaml.snakeyaml.error.YAMLException;
+
+/**
+ * <p>
+ * A <code>MethodProperty</code> is a <code>Property</code> which is accessed
+ * through accessor methods (setX, getX). It is possible to have a
+ * <code>MethodProperty</code> which has only setter, only getter, or both. It
+ * is not possible to have a <code>MethodProperty</code> which has neither
+ * setter nor getter.
+ * </p>
+ */
+public class MethodProperty extends GenericProperty {
+
+ private final PropertyDescriptor property;
+ private final boolean readable;
+ private final boolean writable;
+
+ public MethodProperty(PropertyDescriptor property) {
+ super(property.getName(), property.getPropertyType(),
+ property.getReadMethod() == null ? null : property.getReadMethod()
+ .getGenericReturnType());
+ this.property = property;
+ this.readable = property.getReadMethod() != null;
+ this.writable = property.getWriteMethod() != null;
+ }
+
+ @Override
+ public void set(Object object, Object value) throws Exception {
+ property.getWriteMethod().invoke(object, value);
+ }
+
+ @Override
+ public Object get(Object object) {
+ try {
+ property.getReadMethod().setAccessible(true);// issue 50
+ return property.getReadMethod().invoke(object);
+ } catch (Exception e) {
+ throw new YAMLException("Unable to find getter for property '" + property.getName()
+ + "' on object " + object + ":" + e);
+ }
+ }
+
+ @Override
+ public boolean isWritable() {
+ return writable;
+ }
+
+ @Override
+ public boolean isReadable() {
+ return readable;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/org/yaml/snakeyaml/introspector/MissingProperty.java b/src/main/java/org/yaml/snakeyaml/introspector/MissingProperty.java
new file mode 100644
index 0000000..b16a1c2
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/introspector/MissingProperty.java
@@ -0,0 +1,44 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.introspector;
+
+/**
+ * A property that does not map to a real property; this is used when {@link
+ * PropertyUtils.setSkipMissingProperties(boolean)} is set to true.
+ */
+public class MissingProperty extends Property {
+
+ public MissingProperty(String name) {
+ super(name, Object.class);
+ }
+
+ @Override
+ public Class<?>[] getActualTypeArguments() {
+ return new Class[0];
+ }
+
+ /**
+ * Setter does nothing.
+ */
+ @Override
+ public void set(Object object, Object value) throws Exception {
+ }
+
+ @Override
+ public Object get(Object object) {
+ return object;
+ }
+}
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 0000000..286ca0e
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/introspector/Property.java
@@ -0,0 +1,85 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.introspector;
+
+/**
+ * <p>
+ * A <code>Property</code> represents a single member variable of a class,
+ * possibly including its accessor methods (getX, setX). The name stored in this
+ * class is the actual name of the property as given for the class, not an
+ * alias.
+ * </p>
+ *
+ * <p>
+ * Objects of this class have a total ordering which defaults to ordering based
+ * on the name of the property.
+ * </p>
+ */
+public abstract class Property implements Comparable<Property> {
+
+ private final String name;
+ private final Class<?> type;
+
+ public Property(String name, Class<?> type) {
+ this.name = name;
+ this.type = type;
+ }
+
+ public Class<?> getType() {
+ return type;
+ }
+
+ abstract public Class<?>[] getActualTypeArguments();
+
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String toString() {
+ return getName() + " of " + getType();
+ }
+
+ public int compareTo(Property o) {
+ return name.compareTo(o.name);
+ }
+
+ public boolean isWritable() {
+ return true;
+ }
+
+ public boolean isReadable() {
+ return true;
+ }
+
+ abstract public void set(Object object, Object value) throws Exception;
+
+ abstract public Object get(Object object);
+
+ @Override
+ public int hashCode() {
+ return name.hashCode() + type.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other instanceof Property) {
+ Property p = (Property) other;
+ return name.equals(p.getName()) && type.equals(p.getType());
+ }
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/org/yaml/snakeyaml/introspector/PropertyUtils.java b/src/main/java/org/yaml/snakeyaml/introspector/PropertyUtils.java
new file mode 100644
index 0000000..92519d9
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/introspector/PropertyUtils.java
@@ -0,0 +1,166 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.introspector;
+
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.yaml.snakeyaml.error.YAMLException;
+
+public class PropertyUtils {
+
+ private final Map<Class<?>, Map<String, Property>> propertiesCache = new HashMap<Class<?>, Map<String, Property>>();
+ private final Map<Class<?>, Set<Property>> readableProperties = new HashMap<Class<?>, Set<Property>>();
+ private BeanAccess beanAccess = BeanAccess.DEFAULT;
+ private boolean allowReadOnlyProperties = false;
+ private boolean skipMissingProperties = false;
+
+ protected Map<String, Property> getPropertiesMap(Class<?> type, BeanAccess bAccess)
+ throws IntrospectionException {
+ if (propertiesCache.containsKey(type)) {
+ return propertiesCache.get(type);
+ }
+
+ Map<String, Property> properties = new LinkedHashMap<String, Property>();
+ boolean inaccessableFieldsExist = false;
+ switch (bAccess) {
+ case FIELD:
+ for (Class<?> c = type; c != null; c = c.getSuperclass()) {
+ for (Field field : c.getDeclaredFields()) {
+ int modifiers = field.getModifiers();
+ if (!Modifier.isStatic(modifiers) && !Modifier.isTransient(modifiers)
+ && !properties.containsKey(field.getName())) {
+ properties.put(field.getName(), new FieldProperty(field));
+ }
+ }
+ }
+ break;
+ default:
+ // add JavaBean properties
+ for (PropertyDescriptor property : Introspector.getBeanInfo(type)
+ .getPropertyDescriptors()) {
+ Method readMethod = property.getReadMethod();
+ if (readMethod == null || !readMethod.getName().equals("getClass")) {
+ properties.put(property.getName(), new MethodProperty(property));
+ }
+ }
+
+ // add public fields
+ for (Class<?> c = type; c != null; c = c.getSuperclass()) {
+ for (Field field : c.getDeclaredFields()) {
+ int modifiers = field.getModifiers();
+ if (!Modifier.isStatic(modifiers) && !Modifier.isTransient(modifiers)) {
+ if (Modifier.isPublic(modifiers)) {
+ properties.put(field.getName(), new FieldProperty(field));
+ } else {
+ inaccessableFieldsExist = true;
+ }
+ }
+ }
+ }
+ break;
+ }
+ if (properties.isEmpty() && inaccessableFieldsExist) {
+ throw new YAMLException("No JavaBean properties found in " + type.getName());
+ }
+ propertiesCache.put(type, properties);
+ return properties;
+ }
+
+ public Set<Property> getProperties(Class<? extends Object> type) throws IntrospectionException {
+ return getProperties(type, beanAccess);
+ }
+
+ public Set<Property> getProperties(Class<? extends Object> type, BeanAccess bAccess)
+ throws IntrospectionException {
+ if (readableProperties.containsKey(type)) {
+ return readableProperties.get(type);
+ }
+ Set<Property> properties = createPropertySet(type, bAccess);
+ readableProperties.put(type, properties);
+ return properties;
+ }
+
+ protected Set<Property> createPropertySet(Class<? extends Object> type, BeanAccess bAccess)
+ throws IntrospectionException {
+ Set<Property> properties = new TreeSet<Property>();
+ Collection<Property> props = getPropertiesMap(type, bAccess).values();
+ for (Property property : props) {
+ if (property.isReadable() && (allowReadOnlyProperties || property.isWritable())) {
+ properties.add(property);
+ }
+ }
+ return properties;
+ }
+
+ public Property getProperty(Class<? extends Object> type, String name)
+ throws IntrospectionException {
+ return getProperty(type, name, beanAccess);
+ }
+
+ public Property getProperty(Class<? extends Object> type, String name, BeanAccess bAccess)
+ throws IntrospectionException {
+ Map<String, Property> properties = getPropertiesMap(type, bAccess);
+ Property property = properties.get(name);
+ if (property == null && skipMissingProperties) {
+ property = new MissingProperty(name);
+ }
+ if (property == null || !property.isWritable()) {
+ throw new YAMLException("Unable to find property '" + name + "' on class: "
+ + type.getName());
+ }
+ return property;
+ }
+
+ public void setBeanAccess(BeanAccess beanAccess) {
+ if (this.beanAccess != beanAccess) {
+ this.beanAccess = beanAccess;
+ propertiesCache.clear();
+ readableProperties.clear();
+ }
+ }
+
+ public void setAllowReadOnlyProperties(boolean allowReadOnlyProperties) {
+ if (this.allowReadOnlyProperties != allowReadOnlyProperties) {
+ this.allowReadOnlyProperties = allowReadOnlyProperties;
+ readableProperties.clear();
+ }
+ }
+
+ /**
+ * Skip properties that are missing during deserialization of YAML to a Java
+ * object. The default is false.
+ *
+ * @param skipMissingProperties
+ * true if missing properties should be skipped, false otherwise.
+ */
+ public void setSkipMissingProperties(boolean skipMissingProperties) {
+ if (this.skipMissingProperties != skipMissingProperties) {
+ this.skipMissingProperties = skipMissingProperties;
+ readableProperties.clear();
+ }
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/nodes/AnchorNode.java b/src/main/java/org/yaml/snakeyaml/nodes/AnchorNode.java
new file mode 100644
index 0000000..8a90131
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/nodes/AnchorNode.java
@@ -0,0 +1,35 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.nodes;
+
+public class AnchorNode extends Node {
+
+ private Node realNode;
+
+ public AnchorNode(Node realNode) {
+ super(realNode.getTag(), realNode.getStartMark(), realNode.getEndMark());
+ this.realNode = realNode;
+ }
+
+ @Override
+ public NodeId getNodeId() {
+ return NodeId.anchor;
+ }
+
+ public Node getRealNode() {
+ return realNode;
+ }
+}
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 0000000..aa44368
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/nodes/CollectionNode.java
@@ -0,0 +1,49 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.nodes;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * Base class for the two collection types {@link MappingNode mapping} and
+ * {@link SequenceNode collection}.
+ */
+public abstract class CollectionNode extends Node {
+ private Boolean flowStyle;
+
+ public CollectionNode(Tag tag, Mark startMark, Mark endMark, Boolean flowStyle) {
+ super(tag, startMark, endMark);
+ this.flowStyle = flowStyle;
+ }
+
+ /**
+ * Serialization style of this collection.
+ *
+ * @return <code>true</code> for flow style, <code>false</code> for block
+ * style.
+ */
+ 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 0000000..ed3dcff
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/nodes/MappingNode.java
@@ -0,0 +1,111 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.nodes;
+
+import java.util.List;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * Represents a map.
+ * <p>
+ * A map is a collection of unsorted key-value pairs.
+ * </p>
+ */
+public class MappingNode extends CollectionNode {
+ private List<NodeTuple> value;
+ private boolean merged = false;
+
+ public MappingNode(Tag tag, boolean resolved, List<NodeTuple> value, Mark startMark,
+ Mark endMark, Boolean flowStyle) {
+ super(tag, startMark, endMark, flowStyle);
+ if (value == null) {
+ throw new NullPointerException("value in a Node is required.");
+ }
+ this.value = value;
+ this.resolved = resolved;
+ }
+
+ public MappingNode(Tag tag, List<NodeTuple> value, Boolean flowStyle) {
+ this(tag, true, value, null, null, flowStyle);
+ }
+
+ @Override
+ public NodeId getNodeId() {
+ return NodeId.mapping;
+ }
+
+ /**
+ * Returns the entries of this map.
+ *
+ * @return List of entries.
+ */
+ public List<NodeTuple> getValue() {
+ return value;
+ }
+
+ public void setValue(List<NodeTuple> merge) {
+ value = merge;
+ }
+
+ public void setOnlyKeyType(Class<? extends Object> keyType) {
+ for (NodeTuple nodes : value) {
+ nodes.getKeyNode().setType(keyType);
+ }
+ }
+
+ public void setTypes(Class<? extends Object> keyType, Class<? extends Object> valueType) {
+ for (NodeTuple nodes : value) {
+ nodes.getValueNode().setType(valueType);
+ nodes.getKeyNode().setType(keyType);
+ }
+ }
+
+ @Override
+ public String toString() {
+ String values;
+ StringBuilder buf = new StringBuilder();
+ for (NodeTuple node : getValue()) {
+ buf.append("{ key=");
+ buf.append(node.getKeyNode());
+ buf.append("; value=");
+ if (node.getValueNode() instanceof CollectionNode) {
+ // to avoid overflow in case of recursive structures
+ buf.append(System.identityHashCode(node.getValueNode()));
+ } else {
+ buf.append(node.toString());
+ }
+ buf.append(" }");
+ }
+ values = buf.toString();
+ return "<" + this.getClass().getName() + " (tag=" + getTag() + ", values=" + values + ")>";
+ }
+
+ /**
+ * @param merged
+ * - true if map contains merge node
+ */
+ public void setMerged(boolean merged) {
+ this.merged = merged;
+ }
+
+ /**
+ * @return true if map contains merge node
+ */
+ public boolean isMerged() {
+ return merged;
+ }
+}
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 0000000..1037e41
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/nodes/Node.java
@@ -0,0 +1,166 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.nodes;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * Base class for all nodes.
+ * <p>
+ * The nodes form the node-graph described in the <a
+ * href="http://yaml.org/spec/1.1/">YAML Specification</a>.
+ * </p>
+ * <p>
+ * While loading, the node graph is usually created by the
+ * {@link org.yaml.snakeyaml.composer.Composer}, and later transformed into
+ * application specific Java classes by the classes from the
+ * {@link org.yaml.snakeyaml.constructor} package.
+ * </p>
+ */
+public abstract class Node {
+ private Tag tag;
+ private Mark startMark;
+ protected Mark endMark;
+ private Class<? extends Object> type;
+ private boolean twoStepsConstruction;
+ /**
+ * true when the tag is assigned by the resolver
+ */
+ protected boolean resolved;
+ protected Boolean useClassConstructor;
+
+ public Node(Tag tag, Mark startMark, Mark endMark) {
+ setTag(tag);
+ this.startMark = startMark;
+ this.endMark = endMark;
+ this.type = Object.class;
+ this.twoStepsConstruction = false;
+ this.resolved = true;
+ this.useClassConstructor = null;
+ }
+
+ /**
+ * Tag of this node.
+ * <p>
+ * Every node has a tag assigned. The tag is either local or global.
+ *
+ * @return Tag of this node.
+ */
+ public Tag getTag() {
+ return this.tag;
+ }
+
+ public Mark getEndMark() {
+ return endMark;
+ }
+
+ /**
+ * 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(Tag tag) {
+ if (tag == null) {
+ throw new NullPointerException("tag in a Node is required.");
+ }
+ this.tag = tag;
+ }
+
+ /**
+ * 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) {
+ if (!type.isAssignableFrom(this.type)) {
+ this.type = type;
+ }
+ }
+
+ public void setTwoStepsConstruction(boolean twoStepsConstruction) {
+ this.twoStepsConstruction = twoStepsConstruction;
+ }
+
+ /**
+ * Indicates if this node must be constructed in two steps.
+ * <p>
+ * Two-step construction is required whenever a node is a child (direct or
+ * indirect) of it self. That is, if a recursive structure is build using
+ * anchors and aliases.
+ * </p>
+ * <p>
+ * Set by {@link org.yaml.snakeyaml.composer.Composer}, used during the
+ * construction process.
+ * </p>
+ * <p>
+ * Only relevant during loading.
+ * </p>
+ *
+ * @return <code>true</code> if the node is self referenced.
+ */
+ public boolean isTwoStepsConstruction() {
+ return twoStepsConstruction;
+ }
+
+ @Override
+ public final int hashCode() {
+ return super.hashCode();
+ }
+
+ public boolean useClassConstructor() {
+ if (useClassConstructor == null) {
+ if (!tag.isSecondary() && isResolved() && !Object.class.equals(type)
+ && !tag.equals(Tag.NULL)) {
+ return true;
+ } else if (tag.isCompatible(getType())) {
+ // the tag is compatible with the runtime class
+ // the tag will be ignored
+ return true;
+ } else {
+ return false;
+ }
+ }
+ return useClassConstructor.booleanValue();
+ }
+
+ public void setUseClassConstructor(Boolean useClassConstructor) {
+ this.useClassConstructor = useClassConstructor;
+ }
+
+ /**
+ * Indicates if the tag was added by
+ * {@link org.yaml.snakeyaml.resolver.Resolver}.
+ *
+ * @return <code>true</code> if the tag of this node was resolved</code>
+ */
+ public boolean isResolved() {
+ return resolved;
+ }
+}
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 0000000..178e26d
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/nodes/NodeId.java
@@ -0,0 +1,23 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.nodes;
+
+/**
+ * Enum for the three basic YAML types: scalar, sequence and mapping.
+ */
+public enum NodeId {
+ scalar, sequence, mapping, anchor;
+}
diff --git a/src/main/java/org/yaml/snakeyaml/nodes/NodeTuple.java b/src/main/java/org/yaml/snakeyaml/nodes/NodeTuple.java
new file mode 100644
index 0000000..3e3cb36
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/nodes/NodeTuple.java
@@ -0,0 +1,55 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.nodes;
+
+/**
+ * Stores one key value pair used in a map.
+ */
+public final class NodeTuple {
+
+ private Node keyNode;
+ private Node valueNode;
+
+ public NodeTuple(Node keyNode, Node valueNode) {
+ if (keyNode == null || valueNode == null) {
+ throw new NullPointerException("Nodes must be provided.");
+ }
+ this.keyNode = keyNode;
+ this.valueNode = valueNode;
+ }
+
+ /**
+ * Key node.
+ */
+ public Node getKeyNode() {
+ return keyNode;
+ }
+
+ /**
+ * Value node.
+ *
+ * @return value
+ */
+ public Node getValueNode() {
+ return valueNode;
+ }
+
+ @Override
+ public String toString() {
+ return "<NodeTuple keyNode=" + keyNode.toString() + "; valueNode=" + valueNode.toString()
+ + ">";
+ }
+}
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 0000000..9120d0e
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/nodes/ScalarNode.java
@@ -0,0 +1,74 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.nodes;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * Represents a scalar node.
+ * <p>
+ * Scalar nodes form the leaves in the node graph.
+ * </p>
+ */
+public class ScalarNode extends Node {
+ private Character style;
+ private String value;
+
+ public ScalarNode(Tag tag, String value, Mark startMark, Mark endMark, Character style) {
+ this(tag, true, value, startMark, endMark, style);
+ }
+
+ public ScalarNode(Tag tag, boolean resolved, String value, Mark startMark, Mark endMark,
+ Character style) {
+ super(tag, startMark, endMark);
+ if (value == null) {
+ throw new NullPointerException("value in a Node is required.");
+ }
+ this.value = value;
+ this.style = style;
+ this.resolved = resolved;
+ }
+
+ /**
+ * Get scalar style of this node.
+ *
+ * @see org.yaml.snakeyaml.events.ScalarEvent
+ * @see <a href="http://yaml.org/spec/1.1/#id903915">Chapter 9. Scalar
+ * Styles</a>
+ */
+ public Character getStyle() {
+ return style;
+ }
+
+ @Override
+ public NodeId getNodeId() {
+ return NodeId.scalar;
+ }
+
+ /**
+ * Value of this scalar.
+ *
+ * @return Scalar's value.
+ */
+ public String getValue() {
+ return value;
+ }
+
+ public String toString() {
+ return "<" + this.getClass().getName() + " (tag=" + getTag() + ", value=" + getValue()
+ + ")>";
+ }
+}
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 0000000..5e2f6b4
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/nodes/SequenceNode.java
@@ -0,0 +1,69 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.nodes;
+
+import java.util.List;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * Represents a sequence.
+ * <p>
+ * A sequence is a ordered collection of nodes.
+ * </p>
+ */
+public class SequenceNode extends CollectionNode {
+ final private List<Node> value;
+
+ public SequenceNode(Tag tag, boolean resolved, List<Node> value, Mark startMark, Mark endMark,
+ Boolean flowStyle) {
+ super(tag, startMark, endMark, flowStyle);
+ if (value == null) {
+ throw new NullPointerException("value in a Node is required.");
+ }
+ this.value = value;
+ this.resolved = resolved;
+ }
+
+ public SequenceNode(Tag tag, List<Node> value, Boolean flowStyle) {
+ this(tag, true, value, null, null, flowStyle);
+ }
+
+ @Override
+ public NodeId getNodeId() {
+ return NodeId.sequence;
+ }
+
+ /**
+ * Returns the elements in this sequence.
+ *
+ * @return Nodes in the specified order.
+ */
+ public List<Node> getValue() {
+ return value;
+ }
+
+ public void setListType(Class<? extends Object> listType) {
+ for (Node node : value) {
+ node.setType(listType);
+ }
+ }
+
+ public String toString() {
+ return "<" + this.getClass().getName() + " (tag=" + getTag() + ", value=" + getValue()
+ + ")>";
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/nodes/Tag.java b/src/main/java/org/yaml/snakeyaml/nodes/Tag.java
new file mode 100644
index 0000000..913e1f5
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/nodes/Tag.java
@@ -0,0 +1,172 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.nodes;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.net.URI;
+import java.sql.Timestamp;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.yaml.snakeyaml.error.YAMLException;
+import org.yaml.snakeyaml.util.UriEncoder;
+
+public final class Tag implements Comparable<Tag> {
+ public static final String PREFIX = "tag:yaml.org,2002:";
+ public static final Tag YAML = new Tag(PREFIX + "yaml");
+ public static final Tag MERGE = new Tag(PREFIX + "merge");
+ public static final Tag SET = new Tag(PREFIX + "set");
+ public static final Tag PAIRS = new Tag(PREFIX + "pairs");
+ public static final Tag OMAP = new Tag(PREFIX + "omap");
+ public static final Tag BINARY = new Tag(PREFIX + "binary");
+ public static final Tag INT = new Tag(PREFIX + "int");
+ public static final Tag FLOAT = new Tag(PREFIX + "float");
+ public static final Tag TIMESTAMP = new Tag(PREFIX + "timestamp");
+ public static final Tag BOOL = new Tag(PREFIX + "bool");
+ public static final Tag NULL = new Tag(PREFIX + "null");
+ public static final Tag STR = new Tag(PREFIX + "str");
+ public static final Tag SEQ = new Tag(PREFIX + "seq");
+ public static final Tag MAP = new Tag(PREFIX + "map");
+ public static final Map<Tag, Set<Class<?>>> COMPATIBILITY_MAP;
+ static {
+ COMPATIBILITY_MAP = new HashMap<Tag, Set<Class<?>>>();
+ Set<Class<?>> floatSet = new HashSet<Class<?>>();
+ floatSet.add(Double.class);
+ floatSet.add(Float.class);
+ floatSet.add(BigDecimal.class);
+ COMPATIBILITY_MAP.put(FLOAT, floatSet);
+ //
+ Set<Class<?>> intSet = new HashSet<Class<?>>();
+ intSet.add(Integer.class);
+ intSet.add(Long.class);
+ intSet.add(BigInteger.class);
+ COMPATIBILITY_MAP.put(INT, intSet);
+ //
+ Set<Class<?>> timestampSet = new HashSet<Class<?>>();
+ timestampSet.add(Date.class);
+ timestampSet.add(java.sql.Date.class);
+ timestampSet.add(Timestamp.class);
+ COMPATIBILITY_MAP.put(TIMESTAMP, timestampSet);
+ }
+
+ private final String value;
+ private boolean secondary = false; // see http://www.yaml.org/refcard.html
+
+ public Tag(String tag) {
+ if (tag == null) {
+ throw new NullPointerException("Tag must be provided.");
+ } else if (tag.length() == 0) {
+ throw new IllegalArgumentException("Tag must not be empty.");
+ } else if (tag.trim().length() != tag.length()) {
+ throw new IllegalArgumentException("Tag must not contain leading or trailing spaces.");
+ }
+ this.value = UriEncoder.encode(tag);
+ this.secondary = !tag.startsWith(PREFIX);
+ }
+
+ public Tag(Class<? extends Object> clazz) {
+ if (clazz == null) {
+ throw new NullPointerException("Class for tag must be provided.");
+ }
+ this.value = Tag.PREFIX + UriEncoder.encode(clazz.getName());
+ }
+
+ //TODO to be removed ?
+ public Tag(URI uri) {
+ if (uri == null) {
+ throw new NullPointerException("URI for tag must be provided.");
+ }
+ this.value = uri.toASCIIString();
+ }
+
+ public boolean isSecondary() {
+ return secondary;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public boolean startsWith(String prefix) {
+ return value.startsWith(prefix);
+ }
+
+ public String getClassName() {
+ if (!value.startsWith(Tag.PREFIX)) {
+ throw new YAMLException("Invalid tag: " + value);
+ }
+ return UriEncoder.decode(value.substring(Tag.PREFIX.length()));
+ }
+
+ public int getLength() {
+ return value.length();
+ }
+
+ @Override
+ public String toString() {
+ return value;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof Tag) {
+ return value.equals(((Tag) obj).getValue());
+ } else
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return value.hashCode();
+ }
+
+ /**
+ * Java has more then 1 class compatible with a language-independent tag
+ * (!!int, !!float, !!timestamp etc)
+ *
+ * @param clazz
+ * - Class to check compatibility
+ * @return true when the Class can be represented by this
+ * language-independent tag
+ */
+ public boolean isCompatible(Class<?> clazz) {
+ Set<Class<?>> set = COMPATIBILITY_MAP.get(this);
+ if (set != null) {
+ return set.contains(clazz);
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Check whether this tag matches the global tag for the Class
+ *
+ * @param clazz
+ * - Class to check
+ * @return true when the this tag can be used as a global tag for the Class
+ */
+ public boolean matches(Class<? extends Object> clazz) {
+ return value.equals(Tag.PREFIX + clazz.getName());
+ }
+
+ public int compareTo(Tag o) {
+ return value.compareTo(o.getValue());
+ }
+}
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 0000000..8c1bf16
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/parser/Parser.java
@@ -0,0 +1,65 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.parser;
+
+import org.yaml.snakeyaml.events.Event;
+
+/**
+ * This interface represents an input stream of {@link Event Events}.
+ * <p>
+ * The parser and the scanner form together the 'Parse' step in the loading
+ * process (see chapter 3.1 of the <a href="http://yaml.org/spec/1.1/">YAML
+ * Specification</a>).
+ * </p>
+ *
+ * @see org.yaml.snakeyaml.events.Event
+ */
+public interface Parser {
+
+ /**
+ * Check if the next event is one of the given type.
+ *
+ * @param choice
+ * Event ID.
+ * @return <code>true</code> if the next event can be assigned to a variable
+ * of the given type. Returns <code>false</code> if no more events
+ * are available.
+ * @throws ParserException
+ * Thrown in case of malformed input.
+ */
+ public boolean checkEvent(Event.ID choice);
+
+ /**
+ * Return the next event, but do not delete it from the stream.
+ *
+ * @return The event that will be returned on the next call to
+ * {@link #getEvent}
+ * @throws ParserException
+ * Thrown in case of malformed input.
+ */
+ public Event peekEvent();
+
+ /**
+ * Returns the next event.
+ * <p>
+ * The event will be removed from the stream.
+ * </p>
+ *
+ * @throws ParserException
+ * Thrown in case of malformed input.
+ */
+ 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 0000000..fd4b1f1
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/parser/ParserException.java
@@ -0,0 +1,44 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.parser;
+
+import org.yaml.snakeyaml.error.Mark;
+import org.yaml.snakeyaml.error.MarkedYAMLException;
+
+/**
+ * Exception thrown by the {@link Parser} implementations in case of malformed
+ * input.
+ */
+public class ParserException extends MarkedYAMLException {
+ private static final long serialVersionUID = -2349253802798398038L;
+
+ /**
+ * Constructs an instance.
+ *
+ * @param context
+ * Part of the input document in which vicinity the problem
+ * occurred.
+ * @param contextMark
+ * Position of the <code>context</code> within the document.
+ * @param problem
+ * Part of the input document that caused the problem.
+ * @param problemMark
+ * Position of the <code>problem</code>. within the document.
+ */
+ public ParserException(String context, Mark contextMark, String problem, Mark problemMark) {
+ super(context, contextMark, problem, problemMark, null, 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 0000000..7fea2ee
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/parser/ParserImpl.java
@@ -0,0 +1,794 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.parser;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.yaml.snakeyaml.DumperOptions.Version;
+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.ImplicitTuple;
+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.Tag;
+import org.yaml.snakeyaml.reader.StreamReader;
+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.BlockEntryToken;
+import org.yaml.snakeyaml.tokens.DirectiveToken;
+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.TagTuple;
+import org.yaml.snakeyaml.tokens.Token;
+import org.yaml.snakeyaml.util.ArrayStack;
+
+/**
+ * <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.
+ */
+public class ParserImpl implements Parser {
+ private static final Map<String, String> DEFAULT_TAGS = new HashMap<String, String>();
+ static {
+ DEFAULT_TAGS.put("!", "!");
+ DEFAULT_TAGS.put("!!", Tag.PREFIX);
+ }
+
+ protected final Scanner scanner;
+ private Event currentEvent;
+ private final ArrayStack<Production> states;
+ private final ArrayStack<Mark> marks;
+ private Production state;
+ private VersionTagsTuple directives;
+
+ public ParserImpl(StreamReader reader) {
+ this(new ScannerImpl(reader));
+ }
+
+ public ParserImpl(Scanner scanner) {
+ this.scanner = scanner;
+ currentEvent = null;
+ directives = new VersionTagsTuple(null, new HashMap<String, String>(DEFAULT_TAGS));
+ states = new ArrayStack<Production>(100);
+ marks = new ArrayStack<Mark>(10);
+ state = new ParseStreamStart();
+ }
+
+ /**
+ * Check the type of the next event.
+ */
+ public boolean checkEvent(Event.ID choice) {
+ peekEvent();
+ return currentEvent != null && currentEvent.is(choice);
+ }
+
+ /**
+ * 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.
+ if (!scanner.checkToken(Token.ID.Directive, Token.ID.DocumentStart, Token.ID.StreamEnd)) {
+ directives = new VersionTagsTuple(null, 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.push(new ParseDocumentEnd());
+ state = new ParseBlockNode();
+ return event;
+ } else {
+ Production p = new ParseDocumentStart();
+ return p.produce();
+ }
+ }
+ }
+
+ private class ParseDocumentStart implements Production {
+ public Event produce() {
+ // Parse any extra document end indicators.
+ while (scanner.checkToken(Token.ID.DocumentEnd)) {
+ scanner.getToken();
+ }
+ // Parse an explicit document.
+ Event event;
+ if (!scanner.checkToken(Token.ID.StreamEnd)) {
+ Token token = scanner.peekToken();
+ Mark startMark = token.getStartMark();
+ VersionTagsTuple tuple = processDirectives();
+ if (!scanner.checkToken(Token.ID.DocumentStart)) {
+ throw new ParserException(null, null, "expected '<document start>', but found "
+ + scanner.peekToken().getTokenId(), scanner.peekToken().getStartMark());
+ }
+ token = scanner.getToken();
+ Mark endMark = token.getEndMark();
+ event = new DocumentStartEvent(startMark, endMark, true, tuple.getVersion(),
+ tuple.getTags());
+ states.push(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(Token.ID.DocumentEnd)) {
+ 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() {
+ Event event;
+ if (scanner.checkToken(Token.ID.Directive, Token.ID.DocumentStart,
+ Token.ID.DocumentEnd, Token.ID.StreamEnd)) {
+ event = processEmptyScalar(scanner.peekToken().getStartMark());
+ state = states.pop();
+ return event;
+ } else {
+ Production p = new ParseBlockNode();
+ return p.produce();
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private VersionTagsTuple processDirectives() {
+ Version yamlVersion = null;
+ HashMap<String, String> tagHandles = new HashMap<String, String>();
+ while (scanner.checkToken(Token.ID.Directive)) {
+ @SuppressWarnings("rawtypes")
+ 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());
+ }
+ Integer minor = value.get(1);
+ switch (minor) {
+ case 0:
+ yamlVersion = Version.V1_0;
+ break;
+
+ default:
+ yamlVersion = Version.V1_1;
+ break;
+ }
+ } 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);
+ }
+ }
+ if (yamlVersion != null || !tagHandles.isEmpty()) {
+ // directives in the document found - drop the previous
+ for (String key : DEFAULT_TAGS.keySet()) {
+ // do not overwrite re-defined tags
+ if (!tagHandles.containsKey(key)) {
+ tagHandles.put(key, DEFAULT_TAGS.get(key));
+ }
+ }
+ directives = new VersionTagsTuple(yamlVersion, tagHandles);
+ }
+ return directives;
+ }
+
+ /**
+ * <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(Token.ID.Alias)) {
+ AliasToken token = (AliasToken) scanner.getToken();
+ event = new AliasEvent(token.getValue(), token.getStartMark(), token.getEndMark());
+ state = states.pop();
+ } else {
+ String anchor = null;
+ TagTuple tagTokenTag = null;
+ if (scanner.checkToken(Token.ID.Anchor)) {
+ AnchorToken token = (AnchorToken) scanner.getToken();
+ startMark = token.getStartMark();
+ endMark = token.getEndMark();
+ anchor = token.getValue();
+ if (scanner.checkToken(Token.ID.Tag)) {
+ TagToken tagToken = (TagToken) scanner.getToken();
+ tagMark = tagToken.getStartMark();
+ endMark = tagToken.getEndMark();
+ tagTokenTag = tagToken.getValue();
+ }
+ } else if (scanner.checkToken(Token.ID.Tag)) {
+ TagToken tagToken = (TagToken) scanner.getToken();
+ startMark = tagToken.getStartMark();
+ tagMark = startMark;
+ endMark = tagToken.getEndMark();
+ tagTokenTag = tagToken.getValue();
+ if (scanner.checkToken(Token.ID.Anchor)) {
+ AnchorToken token = (AnchorToken) scanner.getToken();
+ endMark = token.getEndMark();
+ anchor = token.getValue();
+ }
+ }
+ String tag = null;
+ if (tagTokenTag != null) {
+ String handle = tagTokenTag.getHandle();
+ String suffix = tagTokenTag.getSuffix();
+ if (handle != null) {
+ if (!directives.getTags().containsKey(handle)) {
+ throw new ParserException("while parsing a node", startMark,
+ "found undefined tag handle " + handle, tagMark);
+ }
+ tag = directives.getTags().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(Token.ID.BlockEntry)) {
+ endMark = scanner.peekToken().getEndMark();
+ event = new SequenceStartEvent(anchor, tag, implicit, startMark, endMark,
+ Boolean.FALSE);
+ state = new ParseIndentlessSequenceEntry();
+ } else {
+ if (scanner.checkToken(Token.ID.Scalar)) {
+ ScalarToken token = (ScalarToken) scanner.getToken();
+ endMark = token.getEndMark();
+ ImplicitTuple implicitValues;
+ if ((token.getPlain() && tag == null) || "!".equals(tag)) {
+ implicitValues = new ImplicitTuple(true, false);
+ } else if (tag == null) {
+ implicitValues = new ImplicitTuple(false, true);
+ } else {
+ implicitValues = new ImplicitTuple(false, false);
+ }
+ event = new ScalarEvent(anchor, tag, implicitValues, token.getValue(),
+ startMark, endMark, token.getStyle());
+ state = states.pop();
+ } else if (scanner.checkToken(Token.ID.FlowSequenceStart)) {
+ endMark = scanner.peekToken().getEndMark();
+ event = new SequenceStartEvent(anchor, tag, implicit, startMark, endMark,
+ Boolean.TRUE);
+ state = new ParseFlowSequenceFirstEntry();
+ } else if (scanner.checkToken(Token.ID.FlowMappingStart)) {
+ endMark = scanner.peekToken().getEndMark();
+ event = new MappingStartEvent(anchor, tag, implicit, startMark, endMark,
+ Boolean.TRUE);
+ state = new ParseFlowMappingFirstKey();
+ } else if (block && scanner.checkToken(Token.ID.BlockSequenceStart)) {
+ endMark = scanner.peekToken().getStartMark();
+ event = new SequenceStartEvent(anchor, tag, implicit, startMark, endMark,
+ Boolean.FALSE);
+ state = new ParseBlockSequenceFirstEntry();
+ } else if (block && scanner.checkToken(Token.ID.BlockMappingStart)) {
+ 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.
+ event = new ScalarEvent(anchor, tag, new ImplicitTuple(implicit, false), "",
+ startMark, endMark, (char) 0);
+ state = states.pop();
+ } 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.push(token.getStartMark());
+ return new ParseBlockSequenceEntry().produce();
+ }
+ }
+
+ private class ParseBlockSequenceEntry implements Production {
+ public Event produce() {
+ if (scanner.checkToken(Token.ID.BlockEntry)) {
+ BlockEntryToken token = (BlockEntryToken) scanner.getToken();
+ if (!scanner.checkToken(Token.ID.BlockEntry, Token.ID.BlockEnd)) {
+ states.push(new ParseBlockSequenceEntry());
+ return new ParseBlockNode().produce();
+ } else {
+ state = new ParseBlockSequenceEntry();
+ return processEmptyScalar(token.getEndMark());
+ }
+ }
+ if (!scanner.checkToken(Token.ID.BlockEnd)) {
+ Token token = scanner.peekToken();
+ throw new ParserException("while parsing a block collection", marks.pop(),
+ "expected <block end>, but found " + token.getTokenId(),
+ token.getStartMark());
+ }
+ Token token = scanner.getToken();
+ Event event = new SequenceEndEvent(token.getStartMark(), token.getEndMark());
+ state = states.pop();
+ marks.pop();
+ return event;
+ }
+ }
+
+ // indentless_sequence ::= (BLOCK-ENTRY block_node?)+
+
+ private class ParseIndentlessSequenceEntry implements Production {
+ public Event produce() {
+ if (scanner.checkToken(Token.ID.BlockEntry)) {
+ Token token = scanner.getToken();
+ if (!scanner.checkToken(Token.ID.BlockEntry, Token.ID.Key, Token.ID.Value,
+ Token.ID.BlockEnd)) {
+ states.push(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.pop();
+ return event;
+ }
+ }
+
+ private class ParseBlockMappingFirstKey implements Production {
+ public Event produce() {
+ Token token = scanner.getToken();
+ marks.push(token.getStartMark());
+ return new ParseBlockMappingKey().produce();
+ }
+ }
+
+ private class ParseBlockMappingKey implements Production {
+ public Event produce() {
+ if (scanner.checkToken(Token.ID.Key)) {
+ Token token = scanner.getToken();
+ if (!scanner.checkToken(Token.ID.Key, Token.ID.Value, Token.ID.BlockEnd)) {
+ states.push(new ParseBlockMappingValue());
+ return parseBlockNodeOrIndentlessSequence();
+ } else {
+ state = new ParseBlockMappingValue();
+ return processEmptyScalar(token.getEndMark());
+ }
+ }
+ if (!scanner.checkToken(Token.ID.BlockEnd)) {
+ Token token = scanner.peekToken();
+ throw new ParserException("while parsing a block mapping", marks.pop(),
+ "expected <block end>, but found " + token.getTokenId(),
+ token.getStartMark());
+ }
+ Token token = scanner.getToken();
+ Event event = new MappingEndEvent(token.getStartMark(), token.getEndMark());
+ state = states.pop();
+ marks.pop();
+ return event;
+ }
+ }
+
+ private class ParseBlockMappingValue implements Production {
+ public Event produce() {
+ if (scanner.checkToken(Token.ID.Value)) {
+ Token token = scanner.getToken();
+ if (!scanner.checkToken(Token.ID.Key, Token.ID.Value, Token.ID.BlockEnd)) {
+ states.push(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.push(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(Token.ID.FlowSequenceEnd)) {
+ if (!first) {
+ if (scanner.checkToken(Token.ID.FlowEntry)) {
+ scanner.getToken();
+ } else {
+ Token token = scanner.peekToken();
+ throw new ParserException("while parsing a flow sequence", marks.pop(),
+ "expected ',' or ']', but got " + token.getTokenId(),
+ token.getStartMark());
+ }
+ }
+ if (scanner.checkToken(Token.ID.Key)) {
+ 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(Token.ID.FlowSequenceEnd)) {
+ states.push(new ParseFlowSequenceEntry(false));
+ return parseFlowNode();
+ }
+ }
+ Token token = scanner.getToken();
+ Event event = new SequenceEndEvent(token.getStartMark(), token.getEndMark());
+ state = states.pop();
+ marks.pop();
+ return event;
+ }
+ }
+
+ private class ParseFlowSequenceEntryMappingKey implements Production {
+ public Event produce() {
+ Token token = scanner.getToken();
+ if (!scanner.checkToken(Token.ID.Value, Token.ID.FlowEntry, Token.ID.FlowSequenceEnd)) {
+ states.push(new ParseFlowSequenceEntryMappingValue());
+ return parseFlowNode();
+ } else {
+ state = new ParseFlowSequenceEntryMappingValue();
+ return processEmptyScalar(token.getEndMark());
+ }
+ }
+ }
+
+ private class ParseFlowSequenceEntryMappingValue implements Production {
+ public Event produce() {
+ if (scanner.checkToken(Token.ID.Value)) {
+ Token token = scanner.getToken();
+ if (!scanner.checkToken(Token.ID.FlowEntry, Token.ID.FlowSequenceEnd)) {
+ states.push(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.push(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(Token.ID.FlowMappingEnd)) {
+ if (!first) {
+ if (scanner.checkToken(Token.ID.FlowEntry)) {
+ scanner.getToken();
+ } else {
+ Token token = scanner.peekToken();
+ throw new ParserException("while parsing a flow mapping", marks.pop(),
+ "expected ',' or '}', but got " + token.getTokenId(),
+ token.getStartMark());
+ }
+ }
+ if (scanner.checkToken(Token.ID.Key)) {
+ Token token = scanner.getToken();
+ if (!scanner.checkToken(Token.ID.Value, Token.ID.FlowEntry,
+ Token.ID.FlowMappingEnd)) {
+ states.push(new ParseFlowMappingValue());
+ return parseFlowNode();
+ } else {
+ state = new ParseFlowMappingValue();
+ return processEmptyScalar(token.getEndMark());
+ }
+ } else if (!scanner.checkToken(Token.ID.FlowMappingEnd)) {
+ states.push(new ParseFlowMappingEmptyValue());
+ return parseFlowNode();
+ }
+ }
+ Token token = scanner.getToken();
+ Event event = new MappingEndEvent(token.getStartMark(), token.getEndMark());
+ state = states.pop();
+ marks.pop();
+ return event;
+ }
+ }
+
+ private class ParseFlowMappingValue implements Production {
+ public Event produce() {
+ if (scanner.checkToken(Token.ID.Value)) {
+ Token token = scanner.getToken();
+ if (!scanner.checkToken(Token.ID.FlowEntry, Token.ID.FlowMappingEnd)) {
+ states.push(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) {
+ return new ScalarEvent(null, null, new ImplicitTuple(true, false), "", 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 0000000..5dd3949
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/parser/Production.java
@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.parser;
+
+import org.yaml.snakeyaml.events.Event;
+
+/**
+ * Helper for {@link ParserImpl}. A grammar rule to apply given the symbols on
+ * top of its stack and the next input token
+ *
+ * @see <a href="http://en.wikipedia.org/wiki/LL_parser"></a>
+ */
+interface Production {
+ Event produce();
+}
diff --git a/src/main/java/org/yaml/snakeyaml/parser/VersionTagsTuple.java b/src/main/java/org/yaml/snakeyaml/parser/VersionTagsTuple.java
new file mode 100644
index 0000000..44ed2fb
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/parser/VersionTagsTuple.java
@@ -0,0 +1,46 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.parser;
+
+import java.util.Map;
+
+import org.yaml.snakeyaml.DumperOptions.Version;
+
+/**
+ * Store the internal state for directives
+ */
+class VersionTagsTuple {
+ private Version version;
+ private Map<String, String> tags;
+
+ public VersionTagsTuple(Version version, Map<String, String> tags) {
+ this.version = version;
+ this.tags = tags;
+ }
+
+ public Version getVersion() {
+ return version;
+ }
+
+ public Map<String, String> getTags() {
+ return tags;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("VersionTagsTuple<%s, %s>", version, tags);
+ }
+}
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 0000000..7a8a06b
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/reader/ReaderException.java
@@ -0,0 +1,51 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.reader;
+
+import org.yaml.snakeyaml.error.YAMLException;
+
+public class ReaderException extends YAMLException {
+ private static final long serialVersionUID = 8710781187529689083L;
+ private final String name;
+ private final char character;
+ private final int position;
+
+ public ReaderException(String name, int position, char character, String message) {
+ super(message);
+ this.name = name;
+ this.character = character;
+ this.position = position;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public char getCharacter() {
+ return character;
+ }
+
+ public int getPosition() {
+ return position;
+ }
+
+ @Override
+ public String toString() {
+ return "unacceptable character '" + character + "' (0x"
+ + Integer.toHexString((int) character).toUpperCase() + ") " + getMessage()
+ + "\nin \"" + name + "\", position " + position;
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/reader/StreamReader.java b/src/main/java/org/yaml/snakeyaml/reader/StreamReader.java
new file mode 100644
index 0000000..56ec007
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/reader/StreamReader.java
@@ -0,0 +1,220 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.reader;
+
+import java.io.IOException;
+import java.io.Reader;
+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;
+import org.yaml.snakeyaml.scanner.Constant;
+
+/**
+ * Reader: checks if characters are in allowed range, adds '\0' to the end.
+ */
+public class StreamReader {
+ public final static Pattern NON_PRINTABLE = Pattern
+ .compile("[^\t\n\r\u0020-\u007E\u0085\u00A0-\uD7FF\uE000-\uFFFD]");
+ private String name;
+ private final Reader stream;
+ private int pointer = 0;
+ private boolean eof = true;
+ private String buffer;
+ private int index = 0;
+ private int line = 0;
+ private int column = 0;
+ private char[] data;
+
+ public StreamReader(String stream) {
+ this.name = "'string'";
+ this.buffer = ""; // to set length to 0
+ checkPrintable(stream);
+ this.buffer = stream + "\0";
+ this.stream = null;
+ this.eof = true;
+ this.data = null;
+ }
+
+ public StreamReader(Reader reader) {
+ this.name = "'reader'";
+ this.buffer = "";
+ this.stream = reader;
+ this.eof = false;
+ this.data = new char[1024];
+ this.update();
+ }
+
+ 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");
+ }
+ }
+
+ /**
+ * Checks <code>chars</chars> for the non-printable characters.
+ *
+ * @param chars
+ * the array where to search.
+ * @param begin
+ * the beginning index, inclusive.
+ * @param end
+ * the ending index, exclusive.
+ * @throws ReaderException
+ * if <code>chars</code> contains non-printable character(s).
+ */
+ void checkPrintable(final char[] chars, final int begin, final int end) {
+ for (int i = begin; i < end; i++) {
+ final char c = chars[i];
+
+ if (isPrintable(c)) {
+ continue;
+ }
+
+ int position = this.index + this.buffer.length() - this.pointer + i;
+ throw new ReaderException(name, position, c, "special characters are not allowed");
+ }
+ }
+
+ public static boolean isPrintable(final char c) {
+ return (c >= '\u0020' && c <= '\u007E') || c == '\n' || c == '\r' || c == '\t'
+ || c == '\u0085' || (c >= '\u00A0' && c <= '\uD7FF')
+ || (c >= '\uE000' && c <= '\uFFFD');
+ }
+
+ public Mark getMark() {
+ return new Mark(name, this.index, this.line, this.column, this.buffer, this.pointer);
+ }
+
+ 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();
+ }
+ char ch = 0;
+ for (int i = 0; i < length; i++) {
+ ch = this.buffer.charAt(this.pointer);
+ this.pointer++;
+ this.index++;
+ if (Constant.LINEBR.has(ch) || (ch == '\r' && buffer.charAt(pointer) != '\n')) {
+ this.line++;
+ this.column = 0;
+ } else if (ch != '\uFEFF') {
+ this.column++;
+ }
+ }
+ }
+
+ public char peek() {
+ return this.buffer.charAt(this.pointer);
+ }
+
+ /**
+ * Peek the next index-th character
+ *
+ * @param index
+ * @return the next index-th character
+ */
+ public char peek(int index) {
+ if (this.pointer + index + 1 > this.buffer.length()) {
+ update();
+ }
+ return this.buffer.charAt(this.pointer + index);
+ }
+
+ /**
+ * peek the next length characters
+ *
+ * @param length
+ * @return the next length characters
+ */
+ public String prefix(int length) {
+ if (this.pointer + length >= this.buffer.length()) {
+ update();
+ }
+ if (this.pointer + length > this.buffer.length()) {
+ return this.buffer.substring(this.pointer);
+ }
+ return this.buffer.substring(this.pointer, this.pointer + length);
+ }
+
+ /**
+ * prefix(length) immediately followed by forward(length)
+ */
+ public String prefixForward(int length) {
+ final String prefix = prefix(length);
+ this.pointer += length;
+ this.index += length;
+ // prefix never contains new line characters
+ this.column += length;
+ return prefix;
+ }
+
+ private void update() {
+ if (!this.eof) {
+ this.buffer = buffer.substring(this.pointer);
+ this.pointer = 0;
+ try {
+ int converted = this.stream.read(data);
+ if (converted > 0) {
+ /*
+ * Let's create StringBuilder manually. Anyway str1 + str2
+ * generates new StringBuilder(str1).append(str2).toSting()
+ * Giving correct capacity to the constructor prevents
+ * unnecessary operations in appends.
+ */
+ checkPrintable(data, 0, converted);
+ this.buffer = new StringBuilder(buffer.length() + converted).append(buffer)
+ .append(data, 0, converted).toString();
+ } else {
+ this.eof = true;
+ this.buffer += "\0";
+ }
+ } catch (IOException ioe) {
+ throw new YAMLException(ioe);
+ }
+ }
+ }
+
+ 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/UnicodeReader.java b/src/main/java/org/yaml/snakeyaml/reader/UnicodeReader.java
new file mode 100644
index 0000000..dd9dc39
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/reader/UnicodeReader.java
@@ -0,0 +1,125 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+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;
+import java.io.Reader;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CodingErrorAction;
+
+/**
+ * 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 Reader {
+ private static final Charset UTF8 = Charset.forName("UTF-8");
+ private static final Charset UTF16BE = Charset.forName("UTF-16BE");
+ private static final Charset UTF16LE = Charset.forName("UTF-16LE");
+
+ PushbackInputStream internalIn;
+ InputStreamReader internalIn2 = null;
+
+ private static final int BOM_SIZE = 3;
+
+ /**
+ * @param in
+ * InputStream to be read
+ */
+ 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;
+
+ Charset 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 = UTF8;
+ unread = n - 3;
+ } else if ((bom[0] == (byte) 0xFE) && (bom[1] == (byte) 0xFF)) {
+ encoding = UTF16BE;
+ unread = n - 2;
+ } else if ((bom[0] == (byte) 0xFF) && (bom[1] == (byte) 0xFE)) {
+ encoding = UTF16LE;
+ unread = n - 2;
+ } else {
+ // Unicode BOM mark not found, unread all bytes
+ encoding = UTF8;
+ unread = n;
+ }
+
+ if (unread > 0)
+ internalIn.unread(bom, (n - unread), unread);
+
+ // Use given encoding
+ CharsetDecoder decoder = encoding.newDecoder().onUnmappableCharacter(
+ CodingErrorAction.REPORT);
+ internalIn2 = new InputStreamReader(internalIn, decoder);
+ }
+
+ 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 0000000..c4419fb
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/representer/BaseRepresenter.java
@@ -0,0 +1,202 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.representer;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.IdentityHashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.yaml.snakeyaml.DumperOptions.FlowStyle;
+import org.yaml.snakeyaml.DumperOptions.ScalarStyle;
+import org.yaml.snakeyaml.introspector.PropertyUtils;
+import org.yaml.snakeyaml.nodes.AnchorNode;
+import org.yaml.snakeyaml.nodes.MappingNode;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.NodeTuple;
+import org.yaml.snakeyaml.nodes.ScalarNode;
+import org.yaml.snakeyaml.nodes.SequenceNode;
+import org.yaml.snakeyaml.nodes.Tag;
+
+/**
+ * Represent basic YAML structures: scalar, sequence, mapping
+ */
+public abstract class BaseRepresenter {
+ 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;
+ // the order is important (map can be also a sequence of key-values)
+ protected final Map<Class<?>, Represent> multiRepresenters = new LinkedHashMap<Class<?>, Represent>();
+ protected Character defaultScalarStyle;
+ protected FlowStyle defaultFlowStyle = FlowStyle.AUTO;
+ protected final Map<Object, Node> representedObjects = new IdentityHashMap<Object, Node>() {
+ private static final long serialVersionUID = -5576159264232131854L;
+
+ public Node put(Object key, Node value) {
+ return super.put(key, new AnchorNode(value));
+ }
+ };
+
+ protected Object objectToRepresent;
+ private PropertyUtils propertyUtils;
+ private boolean explicitPropertyUtils = false;
+
+ public Node represent(Object data) {
+ Node node = representData(data);
+ representedObjects.clear();
+ objectToRepresent = null;
+ return node;
+ }
+
+ protected final Node representData(Object data) {
+ objectToRepresent = data;
+ // check for identity
+ if (representedObjects.containsKey(objectToRepresent)) {
+ Node node = representedObjects.get(objectToRepresent);
+ return node;
+ }
+ // }
+ // check for null first
+ if (data == null) {
+ Node node = nullRepresenter.representData(null);
+ 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 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(Tag tag, String value, Character style) {
+ if (style == null) {
+ style = this.defaultScalarStyle;
+ }
+ Node node = new ScalarNode(tag, value, null, null, style);
+ return node;
+ }
+
+ protected Node representScalar(Tag tag, String value) {
+ return representScalar(tag, value, null);
+ }
+
+ protected Node representSequence(Tag tag, Iterable<?> sequence, Boolean flowStyle) {
+ int size = 10;// default for ArrayList
+ if (sequence instanceof List<?>) {
+ size = ((List<?>) sequence).size();
+ }
+ List<Node> value = new ArrayList<Node>(size);
+ SequenceNode node = new SequenceNode(tag, value, flowStyle);
+ representedObjects.put(objectToRepresent, 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 != FlowStyle.AUTO) {
+ node.setFlowStyle(defaultFlowStyle.getStyleBoolean());
+ } else {
+ node.setFlowStyle(bestStyle);
+ }
+ }
+ return node;
+ }
+
+ protected Node representMapping(Tag tag, Map<?, ?> mapping, Boolean flowStyle) {
+ List<NodeTuple> value = new ArrayList<NodeTuple>(mapping.size());
+ MappingNode node = new MappingNode(tag, value, flowStyle);
+ representedObjects.put(objectToRepresent, node);
+ boolean bestStyle = true;
+ for (Map.Entry<?, ?> entry : mapping.entrySet()) {
+ Node nodeKey = representData(entry.getKey());
+ Node nodeValue = representData(entry.getValue());
+ if (!(nodeKey instanceof ScalarNode && ((ScalarNode) nodeKey).getStyle() == null)) {
+ bestStyle = false;
+ }
+ if (!(nodeValue instanceof ScalarNode && ((ScalarNode) nodeValue).getStyle() == null)) {
+ bestStyle = false;
+ }
+ value.add(new NodeTuple(nodeKey, nodeValue));
+ }
+ if (flowStyle == null) {
+ if (defaultFlowStyle != FlowStyle.AUTO) {
+ node.setFlowStyle(defaultFlowStyle.getStyleBoolean());
+ } else {
+ node.setFlowStyle(bestStyle);
+ }
+ }
+ return node;
+ }
+
+ public void setDefaultScalarStyle(ScalarStyle defaultStyle) {
+ this.defaultScalarStyle = defaultStyle.getChar();
+ }
+
+ public void setDefaultFlowStyle(FlowStyle defaultFlowStyle) {
+ this.defaultFlowStyle = defaultFlowStyle;
+ }
+
+ public FlowStyle getDefaultFlowStyle() {
+ return this.defaultFlowStyle;
+ }
+
+ public void setPropertyUtils(PropertyUtils propertyUtils) {
+ this.propertyUtils = propertyUtils;
+ this.explicitPropertyUtils = true;
+ }
+
+ public final PropertyUtils getPropertyUtils() {
+ if (propertyUtils == null) {
+ propertyUtils = new PropertyUtils();
+ }
+ return propertyUtils;
+ }
+
+ public final boolean isExplicitPropertyUtils() {
+ return explicitPropertyUtils;
+ }
+}
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 0000000..55629ed
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/representer/Represent.java
@@ -0,0 +1,36 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.representer;
+
+import org.yaml.snakeyaml.nodes.Node;
+
+/**
+ * Create a Node Graph out of the provided Native Data Structure (Java
+ * instance).
+ *
+ * @see <a href="http://yaml.org/spec/1.1/#id859109">Chapter 3. Processing YAML
+ * Information</a>
+ */
+public interface Represent {
+ /**
+ * Create a Node
+ *
+ * @param data
+ * the instance to represent
+ * @return Node to dump
+ */
+ 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 0000000..e83a5ea
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/representer/Representer.java
@@ -0,0 +1,248 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.representer;
+
+import java.beans.IntrospectionException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.yaml.snakeyaml.DumperOptions.FlowStyle;
+import org.yaml.snakeyaml.error.YAMLException;
+import org.yaml.snakeyaml.introspector.Property;
+import org.yaml.snakeyaml.nodes.MappingNode;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.NodeId;
+import org.yaml.snakeyaml.nodes.NodeTuple;
+import org.yaml.snakeyaml.nodes.ScalarNode;
+import org.yaml.snakeyaml.nodes.SequenceNode;
+import org.yaml.snakeyaml.nodes.Tag;
+
+/**
+ * Represent JavaBeans
+ */
+public class Representer extends SafeRepresenter {
+
+ public Representer() {
+ this.representers.put(null, new RepresentJavaBean());
+ }
+
+ protected class RepresentJavaBean implements Represent {
+ public Node representData(Object data) {
+ try {
+ return representJavaBean(getProperties(data.getClass()), data);
+ } catch (IntrospectionException e) {
+ throw new YAMLException(e);
+ }
+ }
+ }
+
+ /**
+ * Tag logic:<br/>
+ * - explicit root tag is set in serializer <br/>
+ * - if there is a predefined class tag it is used<br/>
+ * - a global tag with class name is always used as tag. The JavaBean parent
+ * of the specified JavaBean may set another tag (tag:yaml.org,2002:map)
+ * when the property class is the same as runtime class
+ *
+ * @param properties
+ * JavaBean getters
+ * @param javaBean
+ * instance for Node
+ * @return Node to get serialized
+ */
+ protected MappingNode representJavaBean(Set<Property> properties, Object javaBean) {
+ List<NodeTuple> value = new ArrayList<NodeTuple>(properties.size());
+ Tag tag;
+ Tag customTag = classTags.get(javaBean.getClass());
+ tag = customTag != null ? customTag : new Tag(javaBean.getClass());
+ // flow style will be chosen by BaseRepresenter
+ MappingNode node = new MappingNode(tag, value, null);
+ representedObjects.put(javaBean, node);
+ boolean bestStyle = true;
+ for (Property property : properties) {
+ Object memberValue = property.get(javaBean);
+ Tag customPropertyTag = memberValue == null ? null : classTags.get(memberValue
+ .getClass());
+ NodeTuple tuple = representJavaBeanProperty(javaBean, property, memberValue,
+ customPropertyTag);
+ if (tuple == null) {
+ continue;
+ }
+ if (((ScalarNode) tuple.getKeyNode()).getStyle() != null) {
+ bestStyle = false;
+ }
+ Node nodeValue = tuple.getValueNode();
+ if (!(nodeValue instanceof ScalarNode && ((ScalarNode) nodeValue).getStyle() == null)) {
+ bestStyle = false;
+ }
+ value.add(tuple);
+ }
+ if (defaultFlowStyle != FlowStyle.AUTO) {
+ node.setFlowStyle(defaultFlowStyle.getStyleBoolean());
+ } else {
+ node.setFlowStyle(bestStyle);
+ }
+ return node;
+ }
+
+ /**
+ * Represent one JavaBean property.
+ *
+ * @param javaBean
+ * - the instance to be represented
+ * @param property
+ * - the property of the instance
+ * @param propertyValue
+ * - value to be represented
+ * @param customTag
+ * - user defined Tag
+ * @return NodeTuple to be used in a MappingNode. Return null to skip the
+ * property
+ */
+ protected NodeTuple representJavaBeanProperty(Object javaBean, Property property,
+ Object propertyValue, Tag customTag) {
+ ScalarNode nodeKey = (ScalarNode) representData(property.getName());
+ // the first occurrence of the node must keep the tag
+ boolean hasAlias = this.representedObjects.containsKey(propertyValue);
+
+ Node nodeValue = representData(propertyValue);
+
+ if (propertyValue != null && !hasAlias) {
+ NodeId nodeId = nodeValue.getNodeId();
+ if (customTag == null) {
+ if (nodeId == NodeId.scalar) {
+ if (propertyValue instanceof Enum<?>) {
+ nodeValue.setTag(Tag.STR);
+ }
+ } else {
+ if (nodeId == NodeId.mapping) {
+ if (property.getType() == propertyValue.getClass()) {
+ if (!(propertyValue instanceof Map<?, ?>)) {
+ if (!nodeValue.getTag().equals(Tag.SET)) {
+ nodeValue.setTag(Tag.MAP);
+ }
+ }
+ }
+ }
+ checkGlobalTag(property, nodeValue, propertyValue);
+ }
+ }
+ }
+
+ return new NodeTuple(nodeKey, nodeValue);
+ }
+
+ /**
+ * Remove redundant global tag for a type safe (generic) collection if it is
+ * the same as defined by the JavaBean property
+ *
+ * @param property
+ * - JavaBean property
+ * @param node
+ * - representation of the property
+ * @param object
+ * - instance represented by the node
+ */
+ @SuppressWarnings("unchecked")
+ protected void checkGlobalTag(Property property, Node node, Object object) {
+ // Skip primitive arrays.
+ if (object.getClass().isArray() && object.getClass().getComponentType().isPrimitive()) {
+ return;
+ }
+
+ Class<?>[] arguments = property.getActualTypeArguments();
+ if (arguments != null) {
+ if (node.getNodeId() == NodeId.sequence) {
+ // apply map tag where class is the same
+ Class<? extends Object> t = arguments[0];
+ SequenceNode snode = (SequenceNode) node;
+ Iterable<Object> memberList = Collections.EMPTY_LIST;
+ if (object.getClass().isArray()) {
+ memberList = Arrays.asList((Object[]) object);
+ } else if (object instanceof Iterable<?>) {
+ // list
+ memberList = (Iterable<Object>) object;
+ }
+ Iterator<Object> iter = memberList.iterator();
+ if (iter.hasNext()) {
+ for (Node childNode : snode.getValue()) {
+ Object member = iter.next();
+ if (member != null) {
+ if (t.equals(member.getClass()))
+ if (childNode.getNodeId() == NodeId.mapping) {
+ childNode.setTag(Tag.MAP);
+ }
+ }
+ }
+ }
+ } else if (object instanceof Set) {
+ Class<?> t = arguments[0];
+ MappingNode mnode = (MappingNode) node;
+ Iterator<NodeTuple> iter = mnode.getValue().iterator();
+ Set<?> set = (Set<?>) object;
+ for (Object member : set) {
+ NodeTuple tuple = iter.next();
+ Node keyNode = tuple.getKeyNode();
+ if (t.equals(member.getClass())) {
+ if (keyNode.getNodeId() == NodeId.mapping) {
+ keyNode.setTag(Tag.MAP);
+ }
+ }
+ }
+ } else if (object instanceof Map) {
+ Class<?> keyType = arguments[0];
+ Class<?> valueType = arguments[1];
+ MappingNode mnode = (MappingNode) node;
+ for (NodeTuple tuple : mnode.getValue()) {
+ resetTag(keyType, tuple.getKeyNode());
+ resetTag(valueType, tuple.getValueNode());
+ }
+ } else {
+ // the type for collection entries cannot be
+ // detected
+ }
+ }
+ }
+
+ private void resetTag(Class<? extends Object> type, Node node) {
+ Tag tag = node.getTag();
+ if (tag.matches(type)) {
+ if (Enum.class.isAssignableFrom(type)) {
+ node.setTag(Tag.STR);
+ } else {
+ node.setTag(Tag.MAP);
+ }
+ }
+ }
+
+ /**
+ * Get JavaBean properties to be serialised. The order is respected. This
+ * method may be overridden to provide custom property selection or order.
+ *
+ * @param type
+ * - JavaBean to inspect the properties
+ * @return properties to serialise
+ */
+ protected Set<Property> getProperties(Class<? extends Object> type)
+ throws IntrospectionException {
+ return getPropertyUtils().getProperties(type);
+ }
+}
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 0000000..147e3af
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/representer/SafeRepresenter.java
@@ -0,0 +1,426 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.representer;
+
+import java.io.UnsupportedEncodingException;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TimeZone;
+import java.util.UUID;
+import java.util.regex.Pattern;
+
+import org.yaml.snakeyaml.error.YAMLException;
+import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.Tag;
+import org.yaml.snakeyaml.reader.StreamReader;
+
+/**
+ * Represent standard Java classes
+ */
+class SafeRepresenter extends BaseRepresenter {
+
+ protected Map<Class<? extends Object>, Tag> classTags;
+ protected TimeZone timeZone = null;
+
+ public SafeRepresenter() {
+ 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(UUID.class, new RepresentUuid());
+ this.representers.put(byte[].class, new RepresentByteArray());
+
+ Represent primitiveArray = new RepresentPrimitiveArray();
+ representers.put(short[].class, primitiveArray);
+ representers.put(int[].class, primitiveArray);
+ representers.put(long[].class, primitiveArray);
+ representers.put(float[].class, primitiveArray);
+ representers.put(double[].class, primitiveArray);
+ representers.put(char[].class, primitiveArray);
+ representers.put(boolean[].class, primitiveArray);
+
+ 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(Iterator.class, new RepresentIterator());
+ this.multiRepresenters.put(new Object[0].getClass(), new RepresentArray());
+ this.multiRepresenters.put(Date.class, new RepresentDate());
+ this.multiRepresenters.put(Enum.class, new RepresentEnum());
+ this.multiRepresenters.put(Calendar.class, new RepresentDate());
+ classTags = new HashMap<Class<? extends Object>, Tag>();
+ }
+
+ protected Tag getTag(Class<?> clazz, Tag defaultTag) {
+ if (classTags.containsKey(clazz)) {
+ return classTags.get(clazz);
+ } else {
+ return defaultTag;
+ }
+ }
+
+ /**
+ * Define a tag for the <code>Class</code> to serialize.
+ *
+ * @param clazz
+ * <code>Class</code> which tag is changed
+ * @param tag
+ * new tag to be used for every instance of the specified
+ * <code>Class</code>
+ * @return the previous tag associated with the <code>Class</code>
+ */
+ public Tag addClassTag(Class<? extends Object> clazz, Tag tag) {
+ if (tag == null) {
+ throw new NullPointerException("Tag must be provided.");
+ }
+ return classTags.put(clazz, tag);
+ }
+
+ protected class RepresentNull implements Represent {
+ public Node representData(Object data) {
+ return representScalar(Tag.NULL, "null");
+ }
+ }
+
+ public static Pattern MULTILINE_PATTERN = Pattern.compile("\n|\u0085|\u2028|\u2029");
+
+ protected class RepresentString implements Represent {
+ public Node representData(Object data) {
+ Tag tag = Tag.STR;
+ Character style = null;
+ String value = data.toString();
+ if (StreamReader.NON_PRINTABLE.matcher(value).find()) {
+ tag = Tag.BINARY;
+ char[] binary;
+ try {
+ binary = Base64Coder.encode(value.getBytes("UTF-8"));
+ } catch (UnsupportedEncodingException e) {
+ throw new YAMLException(e);
+ }
+ value = String.valueOf(binary);
+ style = '|';
+ }
+ // if no other scalar style is explicitly set, use literal style for
+ // multiline scalars
+ if (defaultScalarStyle == null && MULTILINE_PATTERN.matcher(value).find()) {
+ style = '|';
+ }
+ return representScalar(tag, value, style);
+ }
+ }
+
+ protected class RepresentBoolean implements Represent {
+ public Node representData(Object data) {
+ String value;
+ if (Boolean.TRUE.equals(data)) {
+ value = "true";
+ } else {
+ value = "false";
+ }
+ return representScalar(Tag.BOOL, value);
+ }
+ }
+
+ protected class RepresentNumber implements Represent {
+ public Node representData(Object data) {
+ Tag tag;
+ String value;
+ if (data instanceof Byte || data instanceof Short || data instanceof Integer
+ || data instanceof Long || data instanceof BigInteger) {
+ tag = Tag.INT;
+ value = data.toString();
+ } else {
+ Number number = (Number) data;
+ tag = Tag.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(getTag(data.getClass(), tag), value);
+ }
+ }
+
+ protected class RepresentList implements Represent {
+ @SuppressWarnings("unchecked")
+ public Node representData(Object data) {
+ return representSequence(getTag(data.getClass(), Tag.SEQ), (List<Object>) data, null);
+ }
+ }
+
+ protected class RepresentIterator implements Represent {
+ @SuppressWarnings("unchecked")
+ public Node representData(Object data) {
+ Iterator<Object> iter = (Iterator<Object>) data;
+ return representSequence(getTag(data.getClass(), Tag.SEQ), new IteratorWrapper(iter),
+ null);
+ }
+ }
+
+ private static class IteratorWrapper implements Iterable<Object> {
+ private Iterator<Object> iter;
+
+ public IteratorWrapper(Iterator<Object> iter) {
+ this.iter = iter;
+ }
+
+ public Iterator<Object> iterator() {
+ return iter;
+ }
+ }
+
+ protected class RepresentArray implements Represent {
+ public Node representData(Object data) {
+ Object[] array = (Object[]) data;
+ List<Object> list = Arrays.asList(array);
+ return representSequence(Tag.SEQ, list, null);
+ }
+ }
+
+ /**
+ * Represents primitive arrays, such as short[] and float[], by converting
+ * them into equivalent List<Short> and List<Float> using the appropriate
+ * autoboxing type.
+ */
+ protected class RepresentPrimitiveArray implements Represent {
+ public Node representData(Object data) {
+ Class<?> type = data.getClass().getComponentType();
+
+ if (byte.class == type) {
+ return representSequence(Tag.SEQ, asByteList(data), null);
+ } else if (short.class == type) {
+ return representSequence(Tag.SEQ, asShortList(data), null);
+ } else if (int.class == type) {
+ return representSequence(Tag.SEQ, asIntList(data), null);
+ } else if (long.class == type) {
+ return representSequence(Tag.SEQ, asLongList(data), null);
+ } else if (float.class == type) {
+ return representSequence(Tag.SEQ, asFloatList(data), null);
+ } else if (double.class == type) {
+ return representSequence(Tag.SEQ, asDoubleList(data), null);
+ } else if (char.class == type) {
+ return representSequence(Tag.SEQ, asCharList(data), null);
+ } else if (boolean.class == type) {
+ return representSequence(Tag.SEQ, asBooleanList(data), null);
+ }
+
+ throw new YAMLException("Unexpected primitive '" + type.getCanonicalName() + "'");
+ }
+
+ private List<Byte> asByteList(Object in) {
+ byte[] array = (byte[]) in;
+ List<Byte> list = new ArrayList<Byte>(array.length);
+ for (int i = 0; i < array.length; ++i)
+ list.add(array[i]);
+ return list;
+ }
+
+ private List<Short> asShortList(Object in) {
+ short[] array = (short[]) in;
+ List<Short> list = new ArrayList<Short>(array.length);
+ for (int i = 0; i < array.length; ++i)
+ list.add(array[i]);
+ return list;
+ }
+
+ private List<Integer> asIntList(Object in) {
+ int[] array = (int[]) in;
+ List<Integer> list = new ArrayList<Integer>(array.length);
+ for (int i = 0; i < array.length; ++i)
+ list.add(array[i]);
+ return list;
+ }
+
+ private List<Long> asLongList(Object in) {
+ long[] array = (long[]) in;
+ List<Long> list = new ArrayList<Long>(array.length);
+ for (int i = 0; i < array.length; ++i)
+ list.add(array[i]);
+ return list;
+ }
+
+ private List<Float> asFloatList(Object in) {
+ float[] array = (float[]) in;
+ List<Float> list = new ArrayList<Float>(array.length);
+ for (int i = 0; i < array.length; ++i)
+ list.add(array[i]);
+ return list;
+ }
+
+ private List<Double> asDoubleList(Object in) {
+ double[] array = (double[]) in;
+ List<Double> list = new ArrayList<Double>(array.length);
+ for (int i = 0; i < array.length; ++i)
+ list.add(array[i]);
+ return list;
+ }
+
+ private List<Character> asCharList(Object in) {
+ char[] array = (char[]) in;
+ List<Character> list = new ArrayList<Character>(array.length);
+ for (int i = 0; i < array.length; ++i)
+ list.add(array[i]);
+ return list;
+ }
+
+ private List<Boolean> asBooleanList(Object in) {
+ boolean[] array = (boolean[]) in;
+ List<Boolean> list = new ArrayList<Boolean>(array.length);
+ for (int i = 0; i < array.length; ++i)
+ list.add(array[i]);
+ return list;
+ }
+ }
+
+ protected class RepresentMap implements Represent {
+ @SuppressWarnings("unchecked")
+ public Node representData(Object data) {
+ return representMapping(getTag(data.getClass(), Tag.MAP), (Map<Object, Object>) data,
+ null);
+ }
+ }
+
+ protected 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(getTag(data.getClass(), Tag.SET), value, null);
+ }
+ }
+
+ protected class RepresentDate implements Represent {
+ public Node representData(Object data) {
+ // because SimpleDateFormat ignores timezone we have to use Calendar
+ Calendar calendar;
+ if (data instanceof Calendar) {
+ calendar = (Calendar) data;
+ } else {
+ calendar = Calendar.getInstance(getTimeZone() == null ? TimeZone.getTimeZone("UTC")
+ : timeZone);
+ 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);
+ StringBuilder buffer = new StringBuilder(String.valueOf(years));
+ while (buffer.length() < 4) {
+ // ancient years
+ buffer.insert(0, "0");
+ }
+ 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));
+ }
+ if (TimeZone.getTimeZone("UTC").equals(calendar.getTimeZone())) {
+ buffer.append("Z");
+ } else {
+ // Get the Offset from GMT taking DST into account
+ int gmtOffset = calendar.getTimeZone().getOffset(calendar.get(Calendar.ERA),
+ calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH),
+ calendar.get(Calendar.DAY_OF_MONTH), calendar.get(Calendar.DAY_OF_WEEK),
+ calendar.get(Calendar.MILLISECOND));
+ int minutesOffset = gmtOffset / (60 * 1000);
+ int hoursOffset = minutesOffset / 60;
+ int partOfHour = minutesOffset % 60;
+ buffer.append((hoursOffset > 0 ? "+" : "") + hoursOffset + ":"
+ + (partOfHour < 10 ? "0" + partOfHour : partOfHour));
+ }
+ return representScalar(getTag(data.getClass(), Tag.TIMESTAMP), buffer.toString(), null);
+ }
+ }
+
+ protected class RepresentEnum implements Represent {
+ public Node representData(Object data) {
+ Tag tag = new Tag(data.getClass());
+ return representScalar(getTag(data.getClass(), tag), ((Enum<?>) data).name());
+ }
+ }
+
+ protected class RepresentByteArray implements Represent {
+ public Node representData(Object data) {
+ char[] binary = Base64Coder.encode((byte[]) data);
+ return representScalar(Tag.BINARY, String.valueOf(binary), '|');
+ }
+ }
+
+ public TimeZone getTimeZone() {
+ return timeZone;
+ }
+
+ public void setTimeZone(TimeZone timeZone) {
+ this.timeZone = timeZone;
+ }
+
+ protected class RepresentUuid implements Represent {
+ public Node representData(Object data) {
+ return representScalar(getTag(data.getClass(), new Tag(UUID.class)), data.toString());
+ }
+ }
+}
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 0000000..f8ec36f
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/resolver/Resolver.java
@@ -0,0 +1,138 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.resolver;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+import org.yaml.snakeyaml.nodes.NodeId;
+import org.yaml.snakeyaml.nodes.Tag;
+
+/**
+ * Resolver tries to detect a type by content (when the tag is implicit)
+ */
+public class Resolver {
+ public static final Pattern BOOL = Pattern
+ .compile("^(?:yes|Yes|YES|no|No|NO|true|True|TRUE|false|False|FALSE|on|On|ON|off|Off|OFF)$");
+
+ /**
+ * The regular expression is taken from the 1.2 specification but '_'s are
+ * added to keep backwards compatibility
+ */
+ public static final Pattern FLOAT = Pattern
+ .compile("^([-+]?(\\.[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))$");
+ public 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])+)$");
+ public static final Pattern MERGE = Pattern.compile("^(?:<<)$");
+ public static final Pattern NULL = Pattern.compile("^(?:~|null|Null|NULL| )$");
+ public static final Pattern EMPTY = Pattern.compile("^$");
+ public 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])?))?)$");
+ public static final Pattern VALUE = Pattern.compile("^(?:=)$");
+ public static final Pattern YAML = Pattern.compile("^(?:!|&|\\*)$");
+
+ protected Map<Character, List<ResolverTuple>> yamlImplicitResolvers = new HashMap<Character, List<ResolverTuple>>();
+
+ protected void addImplicitResolvers() {
+ addImplicitResolver(Tag.BOOL, BOOL, "yYnNtTfFoO");
+ /*
+ * INT must be before FLOAT because the regular expression for FLOAT
+ * matches INT (see issue 130)
+ * http://code.google.com/p/snakeyaml/issues/detail?id=130
+ */
+ addImplicitResolver(Tag.INT, INT, "-+0123456789");
+ addImplicitResolver(Tag.FLOAT, FLOAT, "-+0123456789.");
+ addImplicitResolver(Tag.MERGE, MERGE, "<");
+ addImplicitResolver(Tag.NULL, NULL, "~nN\0");
+ addImplicitResolver(Tag.NULL, EMPTY, null);
+ addImplicitResolver(Tag.TIMESTAMP, TIMESTAMP, "0123456789");
+ // The following implicit resolver is only for documentation
+ // purposes.
+ // It cannot work
+ // because plain scalars cannot start with '!', '&', or '*'.
+ addImplicitResolver(Tag.YAML, YAML, "!&*");
+ }
+
+ public Resolver() {
+ addImplicitResolvers();
+ }
+
+ public void addImplicitResolver(Tag tag, Pattern regexp, String first) {
+ if (first == null) {
+ List<ResolverTuple> curr = yamlImplicitResolvers.get(null);
+ if (curr == null) {
+ curr = new ArrayList<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 = Character.valueOf(chrs[i]);
+ if (theC == 0) {
+ // special case: for null
+ theC = null;
+ }
+ List<ResolverTuple> curr = yamlImplicitResolvers.get(theC);
+ if (curr == null) {
+ curr = new ArrayList<ResolverTuple>();
+ yamlImplicitResolvers.put(theC, curr);
+ }
+ curr.add(new ResolverTuple(tag, regexp));
+ }
+ }
+ }
+
+ public Tag resolve(NodeId kind, String value, boolean implicit) {
+ if (kind == NodeId.scalar && implicit) {
+ List<ResolverTuple> resolvers = null;
+ if (value.length() == 0) {
+ resolvers = yamlImplicitResolvers.get('\0');
+ } else {
+ resolvers = yamlImplicitResolvers.get(value.charAt(0));
+ }
+ if (resolvers != null) {
+ for (ResolverTuple v : resolvers) {
+ Tag tag = v.getTag();
+ Pattern regexp = v.getRegexp();
+ if (regexp.matcher(value).matches()) {
+ return tag;
+ }
+ }
+ }
+ if (yamlImplicitResolvers.containsKey(null)) {
+ for (ResolverTuple v : yamlImplicitResolvers.get(null)) {
+ Tag tag = v.getTag();
+ Pattern regexp = v.getRegexp();
+ if (regexp.matcher(value).matches()) {
+ return tag;
+ }
+ }
+ }
+ }
+ switch (kind) {
+ case scalar:
+ return Tag.STR;
+ case sequence:
+ return Tag.SEQ;
+ default:
+ return Tag.MAP;
+ }
+ }
+}
\ 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 0000000..3fbfac0
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/resolver/ResolverTuple.java
@@ -0,0 +1,43 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.resolver;
+
+import java.util.regex.Pattern;
+
+import org.yaml.snakeyaml.nodes.Tag;
+
+final class ResolverTuple {
+ private final Tag tag;
+ private final Pattern regexp;
+
+ public ResolverTuple(Tag tag, Pattern regexp) {
+ this.tag = tag;
+ this.regexp = regexp;
+ }
+
+ public Tag 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/Constant.java b/src/main/java/org/yaml/snakeyaml/scanner/Constant.java
new file mode 100644
index 0000000..391bcaa
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/scanner/Constant.java
@@ -0,0 +1,76 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.scanner;
+
+import java.util.Arrays;
+
+public final class Constant {
+ private final static String ALPHA_S = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-_";
+
+ private final static String LINEBR_S = "\n\u0085\u2028\u2029";
+ private final static String FULL_LINEBR_S = "\r" + LINEBR_S;
+ private final static String NULL_OR_LINEBR_S = "\0" + FULL_LINEBR_S;
+ private final static String NULL_BL_LINEBR_S = " " + NULL_OR_LINEBR_S;
+ private final static String NULL_BL_T_LINEBR_S = "\t" + NULL_BL_LINEBR_S;
+ private final static String NULL_BL_T_S = "\0 \t";
+ private final static String URI_CHARS_S = ALPHA_S + "-;/?:@&=+$,_.!~*\'()[]%";
+
+ public final static Constant LINEBR = new Constant(LINEBR_S);
+ public final static Constant FULL_LINEBR = new Constant(FULL_LINEBR_S);
+ public final static Constant NULL_OR_LINEBR = new Constant(NULL_OR_LINEBR_S);
+ public final static Constant NULL_BL_LINEBR = new Constant(NULL_BL_LINEBR_S);
+ public final static Constant NULL_BL_T_LINEBR = new Constant(NULL_BL_T_LINEBR_S);
+ public final static Constant NULL_BL_T = new Constant(NULL_BL_T_S);
+ public final static Constant URI_CHARS = new Constant(URI_CHARS_S);
+
+ public final static Constant ALPHA = new Constant(ALPHA_S);
+
+ private String content;
+ boolean[] contains = new boolean[128];
+ boolean noASCII = false;
+
+ private Constant(String content) {
+ Arrays.fill(contains, false);
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < content.length(); i++) {
+ char ch = content.charAt(i);
+ if (ch < 128)
+ contains[ch] = true;
+ else
+ sb.append(ch);
+ }
+ if (sb.length() > 0) {
+ noASCII = true;
+ this.content = sb.toString();
+ }
+ }
+
+ public boolean has(char ch) {
+ return (ch < 128) ? contains[ch] : noASCII && content.indexOf(ch, 0) != -1;
+ }
+
+ public boolean hasNo(char ch) {
+ return !has(ch);
+ }
+
+ public boolean has(char ch, String additional) {
+ return has(ch) || additional.indexOf(ch, 0) != -1;
+ }
+
+ public boolean hasNo(char ch, String additional) {
+ return !has(ch, additional);
+ }
+}
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 0000000..6fc0d97
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/scanner/Scanner.java
@@ -0,0 +1,65 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.scanner;
+
+import org.yaml.snakeyaml.tokens.Token;
+
+/**
+ * This interface represents an input stream of {@link Token Tokens}.
+ * <p>
+ * The parser and the scanner form together the 'Parse' step in the loading
+ * process (see chapter 3.1 of the <a href="http://yaml.org/spec/1.1/">YAML
+ * Specification</a>).
+ * </p>
+ *
+ * @see org.yaml.snakeyaml.tokens.Token
+ */
+public interface Scanner {
+
+ /**
+ * Check if the next token is one of the given types.
+ *
+ * @param choices
+ * token IDs.
+ * @return <code>true</code> if the next token can be assigned to a variable
+ * of at least one of the given types. Returns <code>false</code> if
+ * no more tokens are available.
+ * @throws ScannerException
+ * Thrown in case of malformed input.
+ */
+ boolean checkToken(Token.ID... choices);
+
+ /**
+ * Return the next token, but do not delete it from the stream.
+ *
+ * @return The token that will be returned on the next call to
+ * {@link #getToken}
+ * @throws ScannerException
+ * Thrown in case of malformed input.
+ */
+ Token peekToken();
+
+ /**
+ * Returns the next token.
+ * <p>
+ * The token will be removed from the stream.
+ * </p>
+ *
+ * @throws ScannerException
+ * Thrown in case of malformed input.
+ */
+ 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 0000000..b4ee9ee
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/scanner/ScannerException.java
@@ -0,0 +1,66 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.scanner;
+
+import org.yaml.snakeyaml.error.Mark;
+import org.yaml.snakeyaml.error.MarkedYAMLException;
+
+/**
+ * Exception thrown by the {@link Scanner} implementations in case of malformed
+ * input.
+ */
+public class ScannerException extends MarkedYAMLException {
+
+ private static final long serialVersionUID = 4782293188600445954L;
+
+ /**
+ * Constructs an instance.
+ *
+ * @param context
+ * Part of the input document in which vicinity the problem
+ * occurred.
+ * @param contextMark
+ * Position of the <code>context</code> within the document.
+ * @param problem
+ * Part of the input document that caused the problem.
+ * @param problemMark
+ * Position of the <code>problem</code> within the document.
+ * @param note
+ * Message for the user with further information about the
+ * problem.
+ */
+ public ScannerException(String context, Mark contextMark, String problem, Mark problemMark,
+ String note) {
+ super(context, contextMark, problem, problemMark, note);
+ }
+
+ /**
+ * Constructs an instance.
+ *
+ * @param context
+ * Part of the input document in which vicinity the problem
+ * occurred.
+ * @param contextMark
+ * Position of the <code>context</code> within the document.
+ * @param problem
+ * Part of the input document that caused the problem.
+ * @param problemMark
+ * Position of the <code>problem</code> within the document.
+ */
+ public ScannerException(String context, Mark contextMark, String problem, Mark problemMark) {
+ this(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 0000000..4272aab
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/scanner/ScannerImpl.java
@@ -0,0 +1,2288 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.scanner;
+
+import java.nio.ByteBuffer;
+import java.nio.charset.CharacterCodingException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+import org.yaml.snakeyaml.error.Mark;
+import org.yaml.snakeyaml.error.YAMLException;
+import org.yaml.snakeyaml.reader.StreamReader;
+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.TagTuple;
+import org.yaml.snakeyaml.tokens.Token;
+import org.yaml.snakeyaml.tokens.ValueToken;
+import org.yaml.snakeyaml.util.ArrayStack;
+import org.yaml.snakeyaml.util.UriEncoder;
+
+/**
+ * <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>
+ */
+public final class ScannerImpl implements Scanner {
+ /**
+ * A regular expression matching characters which are not in the hexadecimal
+ * set (0-9, A-F, a-f).
+ */
+ private final static Pattern NOT_HEXA = Pattern.compile("[^0-9A-Fa-f]");
+
+ /**
+ * A mapping from an escaped character in the input stream to the character
+ * that they should be replaced with.
+ *
+ * YAML defines several common and a few uncommon escape sequences.
+ *
+ * @see <a href="http://www.yaml.org/spec/current.html#id2517668">4.1.6.
+ * Escape Sequences</a>
+ */
+ public final static Map<Character, String> ESCAPE_REPLACEMENTS = new HashMap<Character, String>();
+
+ /**
+ * A mapping from a character to a number of bytes to read-ahead for that
+ * escape sequence. These escape sequences are used to handle unicode
+ * escaping in the following formats, where H is a hexadecimal character:
+ *
+ * <pre>
+ * \xHH : escaped 8-bit Unicode character
+ * \uHHHH : escaped 16-bit Unicode character
+ * \UHHHHHHHH : escaped 32-bit Unicode character
+ * </pre>
+ *
+ * @see <a href="http://yaml.org/spec/1.1/current.html#id872840">5.6. Escape
+ * Sequences</a>
+ */
+ public final static Map<Character, Integer> ESCAPE_CODES = new HashMap<Character, Integer>();
+
+ static {
+ // ASCII null
+ ESCAPE_REPLACEMENTS.put(Character.valueOf('0'), "\0");
+ // ASCII bell
+ ESCAPE_REPLACEMENTS.put(Character.valueOf('a'), "\u0007");
+ // ASCII backspace
+ ESCAPE_REPLACEMENTS.put(Character.valueOf('b'), "\u0008");
+ // ASCII horizontal tab
+ ESCAPE_REPLACEMENTS.put(Character.valueOf('t'), "\u0009");
+ // ASCII newline (line feed; \n maps to 0x0A)
+ ESCAPE_REPLACEMENTS.put(Character.valueOf('n'), "\n");
+ // ASCII vertical tab
+ ESCAPE_REPLACEMENTS.put(Character.valueOf('v'), "\u000B");
+ // ASCII form-feed
+ ESCAPE_REPLACEMENTS.put(Character.valueOf('f'), "\u000C");
+ // carriage-return (\r maps to 0x0D)
+ ESCAPE_REPLACEMENTS.put(Character.valueOf('r'), "\r");
+ // ASCII escape character (Esc)
+ ESCAPE_REPLACEMENTS.put(Character.valueOf('e'), "\u001B");
+ // ASCII space
+ ESCAPE_REPLACEMENTS.put(Character.valueOf(' '), "\u0020");
+ // ASCII double-quote
+ ESCAPE_REPLACEMENTS.put(Character.valueOf('"'), "\"");
+ // ASCII backslash
+ ESCAPE_REPLACEMENTS.put(Character.valueOf('\\'), "\\");
+ // Unicode next line
+ ESCAPE_REPLACEMENTS.put(Character.valueOf('N'), "\u0085");
+ // Unicode non-breaking-space
+ ESCAPE_REPLACEMENTS.put(Character.valueOf('_'), "\u00A0");
+ // Unicode line-separator
+ ESCAPE_REPLACEMENTS.put(Character.valueOf('L'), "\u2028");
+ // Unicode paragraph separator
+ ESCAPE_REPLACEMENTS.put(Character.valueOf('P'), "\u2029");
+
+ // 8-bit Unicode
+ ESCAPE_CODES.put(Character.valueOf('x'), 2);
+ // 16-bit Unicode
+ ESCAPE_CODES.put(Character.valueOf('u'), 4);
+ // 32-bit Unicode (Supplementary characters are supported)
+ ESCAPE_CODES.put(Character.valueOf('U'), 8);
+ }
+ private final StreamReader 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 ArrayStack<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(StreamReader reader) {
+ this.reader = reader;
+ this.tokens = new ArrayList<Token>(100);
+ this.indents = new ArrayStack<Integer>(10);
+ // The order in possibleSimpleKeys is kept for nextPossibleSimpleKey()
+ this.possibleSimpleKeys = new LinkedHashMap<Integer, SimpleKey>();
+ fetchStreamStart();// Add the STREAM-START token.
+ }
+
+ /**
+ * Check whether the next token is one of the given types.
+ */
+ public boolean checkToken(Token.ID... choices) {
+ while (needMoreTokens()) {
+ fetchMoreTokens();
+ }
+ if (!this.tokens.isEmpty()) {
+ if (choices.length == 0) {
+ return true;
+ }
+ // since profiler puts this method on top (it is used a lot), we
+ // should not use 'foreach' here because of the performance reasons
+ Token.ID first = this.tokens.get(0).getTokenId();
+ for (int i = 0; i < choices.length; i++) {
+ if (first == choices[i]) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Return the next token, but do not delete it from the queue.
+ */
+ public Token peekToken() {
+ while (needMoreTokens()) {
+ fetchMoreTokens();
+ }
+ return this.tokens.get(0);
+ }
+
+ /**
+ * Return the next token, removing it from the queue.
+ */
+ public Token getToken() {
+ if (!this.tokens.isEmpty()) {
+ this.tokensTaken++;
+ return this.tokens.remove(0);
+ }
+ return null;
+ }
+
+ // Private methods.
+ /**
+ * Returns true if more tokens should be scanned.
+ */
+ private boolean needMoreTokens() {
+ // If we are done, we do not require more tokens.
+ if (this.done) {
+ return false;
+ }
+ // If we aren't done, but we have no tokens, we need to scan more.
+ 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;
+ }
+
+ /**
+ * Fetch one or more tokens from the StreamReader.
+ */
+ 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, to decide what the next group of tokens
+ // will look like.
+ 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.We do this by
+ // converting escaped characters into their escape sequences. This is a
+ // backwards use of the ESCAPE_REPLACEMENTS map.
+ String chRepresentation = String.valueOf(ch);
+ for (Character s : ESCAPE_REPLACEMENTS.keySet()) {
+ String v = ESCAPE_REPLACEMENTS.get(s);
+ if (v.equals(chRepresentation)) {
+ chRepresentation = "\\" + s;// ' ' -> '\t'
+ break;
+ }
+ }
+ if (ch == '\t')
+ chRepresentation += "(TAB)";
+ String text = String
+ .format("found character '%s' that cannot start any token. (Do not use %s for indentation)",
+ chRepresentation, chRepresentation);
+ throw new ScannerException("while scanning for the next token", null, text,
+ 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
+ */
+ if (!this.possibleSimpleKeys.isEmpty()) {
+ return this.possibleSimpleKeys.values().iterator().next().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() {
+ if (!this.possibleSimpleKeys.isEmpty()) {
+ for (Iterator<SimpleKey> iterator = this.possibleSimpleKeys.values().iterator(); iterator
+ .hasNext();) {
+ SimpleKey key = iterator.next();
+ if ((key.getLine() != reader.getLine())
+ || (reader.getIndex() - key.getIndex() > 1024)) {
+ // If the key is not on the same line as the current
+ // position OR the difference in column between the token
+ // start and the current position is more than the maximum
+ // simple key length, then this cannot be a simple key.
+ if (key.isRequired()) {
+ // If the key was required, this implies an error
+ // condition.
+ throw new ScannerException("while scanning a simple key", key.getMark(),
+ "could not find expected ':'", reader.getMark());
+ }
+ iterator.remove();
+ }
+ }
+ }
+ }
+
+ /**
+ * 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.
+ // A simple key is required if this position is the root flowLevel, AND
+ // the current indentation level is the same as the last indent-level.
+ 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(this.flowLevel, key);
+ }
+ }
+
+ /**
+ * Remove the saved possible key position at the current flow level.
+ */
+ private void removePossibleSimpleKey() {
+ SimpleKey key = possibleSimpleKeys.remove(flowLevel);
+ if (key != null && key.isRequired()) {
+ throw new ScannerException("while scanning a simple key", key.getMark(),
+ "could not find expected ':'", reader.getMark());
+ }
+ }
+
+ // Indentation functions.
+
+ /**
+ * * Handle implicitly ending multiple levels of block nodes by decreased
+ * indentation. This function becomes important on lines 4 and 7 of this
+ * example:
+ *
+ * <pre>
+ * 1) book one:
+ * 2) part one:
+ * 3) chapter one
+ * 4) part two:
+ * 5) chapter one
+ * 6) chapter two
+ * 7) book two:
+ * </pre>
+ *
+ * In flow context, tokens should respect indentation. Actually the
+ * condition should be `self.indent >= 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.pop();
+ 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.push(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 simple keys.
+ removePossibleSimpleKey();
+ this.allowSimpleKey = false;
+ this.possibleSimpleKeys.clear();
+
+ // 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;
+ }
+
+ /**
+ * Fetch a YAML directive. Directives are presentation details that are
+ * interpreted as instructions to the processor. YAML defines two kinds of
+ * directives, YAML and TAG; all other types are reserved for future use.
+ *
+ * @see <a href="http://www.yaml.org/spec/1.1/#id864824"></a>
+ */
+ 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);
+ }
+
+ /**
+ * Fetch a document-start token ("---").
+ */
+ private void fetchDocumentStart() {
+ fetchDocumentIndicator(true);
+ }
+
+ /**
+ * Fetch a document-end token ("...").
+ */
+ private void fetchDocumentEnd() {
+ fetchDocumentIndicator(false);
+ }
+
+ /**
+ * Fetch a document indicator, either "---" for "document-start", or else
+ * "..." for "document-end. The type is chosen by the given boolean.
+ */
+ 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);
+ }
+
+ /**
+ * Fetch a flow-style collection start, which is either a sequence or a
+ * mapping. The type is determined by the given boolean.
+ *
+ * A flow-style collection is in a format similar to JSON. Sequences are
+ * started by '[' and ended by ']'; mappings are started by '{' and ended by
+ * '}'.
+ *
+ * @see <a href="http://www.yaml.org/spec/1.1/#id863975"></a>
+ *
+ * @param isMappingStart
+ */
+ 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);
+ }
+
+ /**
+ * Fetch a flow-style collection end, which is either a sequence or a
+ * mapping. The type is determined by the given boolean.
+ *
+ * A flow-style collection is in a format similar to JSON. Sequences are
+ * started by '[' and ended by ']'; mappings are started by '{' and ended by
+ * '}'.
+ *
+ * @see <a href="http://www.yaml.org/spec/1.1/#id863975"></a>
+ */
+ 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);
+ }
+
+ /**
+ * Fetch an entry in the flow style. Flow-style entries occur either
+ * immediately after the start of a collection, or else after a comma.
+ *
+ * @see <a href="http://www.yaml.org/spec/1.1/#id863975"></a>
+ */
+ 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);
+ }
+
+ /**
+ * Fetch an entry in the block style.
+ *
+ * @see <a href="http://www.yaml.org/spec/1.1/#id863975"></a>
+ */
+ 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);
+ }
+
+ /**
+ * Fetch a key in a block-style mapping.
+ *
+ * @see <a href="http://www.yaml.org/spec/1.1/#id863975"></a>
+ */
+ 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);
+ }
+
+ /**
+ * Fetch a value in a block-style mapping.
+ *
+ * @see <a href="http://www.yaml.org/spec/1.1/#id863975"></a>
+ */
+ private void fetchValue() {
+ // Do we determine a simple key?
+ SimpleKey key = this.possibleSimpleKeys.remove(this.flowLevel);
+ if (key != null) {
+ // Add KEY.
+ 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 caught 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);
+ }
+
+ /**
+ * Fetch an alias, which is a reference to an anchor. Aliases take the
+ * format:
+ *
+ * <pre>
+ * *(anchor name)
+ * </pre>
+ *
+ * @see <a href="http://www.yaml.org/spec/1.1/#id863390"></a>
+ */
+ 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);
+ }
+
+ /**
+ * Fetch an anchor. Anchors take the form:
+ *
+ * <pre>
+ * &(anchor name)
+ * </pre>
+ *
+ * @see <a href="http://www.yaml.org/spec/1.1/#id863390"></a>
+ */
+ 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);
+ }
+
+ /**
+ * Fetch a tag. Tags take a complex form.
+ *
+ * @see <a href="http://www.yaml.org/spec/1.1/#id861700"></a>
+ */
+ 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);
+ }
+
+ /**
+ * Fetch a literal scalar, denoted with a vertical-bar. This is the type
+ * best used for source code and other content, such as binary data, which
+ * must be included verbatim.
+ *
+ * @see <a href="http://www.yaml.org/spec/1.1/#id863975"></a>
+ */
+ private void fetchLiteral() {
+ fetchBlockScalar('|');
+ }
+
+ /**
+ * Fetch a folded scalar, denoted with a greater-than sign. This is the type
+ * best used for long content, such as the text of a chapter or description.
+ *
+ * @see <a href="http://www.yaml.org/spec/1.1/#id863975"></a>
+ */
+ private void fetchFolded() {
+ fetchBlockScalar('>');
+ }
+
+ /**
+ * Fetch a block scalar (literal or folded).
+ *
+ * @see <a href="http://www.yaml.org/spec/1.1/#id863975"></a>
+ *
+ * @param style
+ */
+ 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);
+ }
+
+ /**
+ * Fetch a single-quoted (') scalar.
+ */
+ private void fetchSingle() {
+ fetchFlowScalar('\'');
+ }
+
+ /**
+ * Fetch a double-quoted (") scalar.
+ */
+ private void fetchDouble() {
+ fetchFlowScalar('"');
+ }
+
+ /**
+ * Fetch a flow scalar (single- or double-quoted).
+ *
+ * @see <a href="http://www.yaml.org/spec/1.1/#id863975"></a>
+ *
+ * @param style
+ */
+ 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);
+ }
+
+ /**
+ * Fetch a plain scalar.
+ */
+ 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.
+ /**
+ * Returns true if the next thing on the reader is a directive, given that
+ * the leading '%' has already been checked.
+ *
+ * @see <a href="http://www.yaml.org/spec/1.1/#id864824"></a>
+ */
+ private boolean checkDirective() {
+ // DIRECTIVE: ^ '%' ...
+ // The '%' indicator is already checked.
+ return reader.getColumn() == 0;
+ }
+
+ /**
+ * Returns true if the next thing on the reader is a document-start ("---").
+ * A document-start is always followed immediately by a new line.
+ */
+ private boolean checkDocumentStart() {
+ // DOCUMENT-START: ^ '---' (' '|'\n')
+ if (reader.getColumn() == 0) {
+ if ("---".equals(reader.prefix(3)) && Constant.NULL_BL_T_LINEBR.has(reader.peek(3))) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if the next thing on the reader is a document-end ("..."). A
+ * document-end is always followed immediately by a new line.
+ */
+ private boolean checkDocumentEnd() {
+ // DOCUMENT-END: ^ '...' (' '|'\n')
+ if (reader.getColumn() == 0) {
+ if ("...".equals(reader.prefix(3)) && Constant.NULL_BL_T_LINEBR.has(reader.peek(3))) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if the next thing on the reader is a block token.
+ */
+ private boolean checkBlockEntry() {
+ // BLOCK-ENTRY: '-' (' '|'\n')
+ return Constant.NULL_BL_T_LINEBR.has(reader.peek(1));
+ }
+
+ /**
+ * Returns true if the next thing on the reader is a key token.
+ */
+ private boolean checkKey() {
+ // KEY(flow context): '?'
+ if (this.flowLevel != 0) {
+ return true;
+ } else {
+ // KEY(block context): '?' (' '|'\n')
+ return Constant.NULL_BL_T_LINEBR.has(reader.peek(1));
+ }
+ }
+
+ /**
+ * Returns true if the next thing on the reader is a value token.
+ */
+ private boolean checkValue() {
+ // VALUE(flow context): ':'
+ if (flowLevel != 0) {
+ return true;
+ } else {
+ // VALUE(block context): ':' (' '|'\n')
+ return Constant.NULL_BL_T_LINEBR.has(reader.peek(1));
+ }
+ }
+
+ /**
+ * Returns true if the next thing on the reader is a plain token.
+ */
+ private boolean checkPlain() {
+ /**
+ * <pre>
+ * A plain scalar may start with any non-space character except:
+ * '-', '?', ':', ',', '[', ']', '{', '}',
+ * '#', '&', '*', '!', '|', '>', '\'', '\"',
+ * '%', '@', '`'.
+ *
+ * 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();
+ // If the next char is NOT one of the forbidden chars above or
+ // whitespace, then this is the start of a plain scalar.
+ return Constant.NULL_BL_T_LINEBR.hasNo(ch, "-?:,[]{}#&*!|>\'\"%@`")
+ || (Constant.NULL_BL_T_LINEBR.hasNo(reader.peek(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 <TAB>:
+ * 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 there is a byte order mark (BOM) at the beginning of the stream,
+ // forward past it.
+ if (reader.getIndex() == 0 && reader.peek() == '\uFEFF') {
+ reader.forward();
+ }
+ boolean found = false;
+ while (!found) {
+ int ff = 0;
+ // Peek ahead until we find the first non-space character, then
+ // move forward directly to that character.
+ while (reader.peek(ff) == ' ') {
+ ff++;
+ }
+ if (ff > 0) {
+ reader.forward(ff);
+ }
+ // If the character we have skipped forward to is a comment (#),
+ // then peek ahead until we find the next end of line. YAML
+ // comments are from a # to the next new-line. We then forward
+ // past the comment.
+ if (reader.peek() == '#') {
+ ff = 0;
+ while (Constant.NULL_OR_LINEBR.hasNo(reader.peek(ff))) {
+ ff++;
+ }
+ if (ff > 0) {
+ reader.forward(ff);
+ }
+ }
+ // If we scanned a line break, then (depending on flow level),
+ // simple keys may be allowed.
+ if (scanLineBreak().length() != 0) {// found a line-break
+ if (this.flowLevel == 0) {
+ // Simple keys are allowed at flow-level 0 after a line
+ // break
+ this.allowSimpleKey = true;
+ }
+ } else {
+ found = true;
+ }
+ }
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ private Token scanDirective() {
+ // See the specification for details.
+ Mark startMark = reader.getMark();
+ Mark endMark;
+ reader.forward();
+ String name = scanDirectiveName(startMark);
+ List<?> value = null;
+ if ("YAML".equals(name)) {
+ value = scanYamlDirectiveValue(startMark);
+ endMark = reader.getMark();
+ } else if ("TAG".equals(name)) {
+ value = scanTagDirectiveValue(startMark);
+ endMark = reader.getMark();
+ } else {
+ endMark = reader.getMark();
+ int ff = 0;
+ while (Constant.NULL_OR_LINEBR.hasNo(reader.peek(ff))) {
+ ff++;
+ }
+ if (ff > 0) {
+ reader.forward(ff);
+ }
+ }
+ scanDirectiveIgnoredLine(startMark);
+ return new DirectiveToken(name, value, startMark, endMark);
+ }
+
+ /**
+ * Scan a directive name. Directive names are a series of non-space
+ * characters.
+ *
+ * @see <a href="http://www.yaml.org/spec/1.1/#id895217"></a>
+ */
+ private String scanDirectiveName(Mark startMark) {
+ // See the specification for details.
+ int length = 0;
+ // A Directive-name is a sequence of alphanumeric characters
+ // (a-z,A-Z,0-9). We scan until we find something that isn't.
+ // FIXME this disagrees with the specification.
+ char ch = reader.peek(length);
+ while (Constant.ALPHA.has(ch)) {
+ length++;
+ ch = reader.peek(length);
+ }
+ // If the name would be empty, an error occurs.
+ 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.prefixForward(length);
+ ch = reader.peek();
+ if (Constant.NULL_BL_LINEBR.hasNo(ch)) {
+ 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 (Constant.NULL_BL_LINEBR.hasNo(reader.peek())) {
+ 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;
+ }
+
+ /**
+ * Read a %YAML directive number: this is either the major or the minor
+ * part. Stop reading at a non-digit character (usually either '.' or '\n').
+ *
+ * @see <a href="http://www.yaml.org/spec/1.1/#id895631"></a>
+ * @see <a href="http://www.yaml.org/spec/1.1/#ns-dec-digit"></a>
+ */
+ 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 = Integer.parseInt(reader.prefixForward(length));
+ return value;
+ }
+
+ /**
+ * <p>
+ * Read a %TAG directive value:
+ *
+ * <pre>
+ * s-ignored-space+ c-tag-handle s-ignored-space+ ns-tag-prefix s-l-comments
+ * </pre>
+ *
+ * </p>
+ *
+ * @see <a href="http://www.yaml.org/spec/1.1/#id896044"></a>
+ */
+ 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;
+ }
+
+ /**
+ * Scan a %TAG directive's handle. This is YAML's c-tag-handle.
+ *
+ * @see <a href="http://www.yaml.org/spec/1.1/#id896876"></a>
+ * @param startMark
+ * @return
+ */
+ 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;
+ }
+
+ /**
+ * Scan a %TAG directive's prefix. This is YAML's ns-tag-prefix.
+ *
+ * @see <a href="http://www.yaml.org/spec/1.1/#ns-tag-prefix"></a>
+ */
+ private String scanTagDirectivePrefix(Mark startMark) {
+ // See the specification for details.
+ String value = scanTagUri("directive", startMark);
+ if (Constant.NULL_BL_LINEBR.hasNo(reader.peek())) {
+ 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.
+ int ff = 0;
+ while (reader.peek(ff) == ' ') {
+ ff++;
+ }
+ if (ff > 0) {
+ reader.forward(ff);
+ }
+ if (reader.peek() == '#') {
+ ff = 0;
+ while (Constant.NULL_OR_LINEBR.hasNo(reader.peek(ff))) {
+ ff++;
+ }
+ reader.forward(ff);
+ }
+ char ch = reader.peek();
+ String lineBreak = scanLineBreak();
+ if (lineBreak.length() == 0 && ch != '\0') {
+ throw new ScannerException("while scanning a directive", startMark,
+ "expected a comment or a line break, but found " + ch + "(" + ((int) ch) + ")",
+ reader.getMark());
+ }
+ return lineBreak;
+ }
+
+ /**
+ * <pre>
+ * The specification does not restrict characters for anchors and
+ * aliases. This may lead to problems, for instance, the document:
+ * [ *alias, value ]
+ * can be interpreted in two ways, as
+ * [ "value" ]
+ * and
+ * [ *alias , "value" ]
+ * 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 (Constant.ALPHA.has(ch)) {
+ length++;
+ ch = reader.peek(length);
+ }
+ if (length == 0) {
+ throw new ScannerException("while scanning an " + name, startMark,
+ "expected alphabetic or numeric character, but found " + ch,
+ reader.getMark());
+ }
+ String value = reader.prefixForward(length);
+ ch = reader.peek();
+ if (Constant.NULL_BL_T_LINEBR.hasNo(ch, "?:,]}%@`")) {
+ 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;
+ }
+
+ /**
+ * <p>
+ * Scan a Tag property. A Tag property may be specified in one of three
+ * ways: c-verbatim-tag, c-ns-shorthand-tag, or c-ns-non-specific-tag
+ * </p>
+ *
+ * <p>
+ * c-verbatim-tag takes the form !<ns-uri-char+> and must be delivered
+ * verbatim (as-is) to the application. In particular, verbatim tags are not
+ * subject to tag resolution.
+ * </p>
+ *
+ * <p>
+ * c-ns-shorthand-tag is a valid tag handle followed by a non-empty suffix.
+ * If the tag handle is a c-primary-tag-handle ('!') then the suffix must
+ * have all exclamation marks properly URI-escaped (%21); otherwise, the
+ * string will look like a named tag handle: !foo!bar would be interpreted
+ * as (handle="!foo!", suffix="bar").
+ * </p>
+ *
+ * <p>
+ * c-ns-non-specific-tag is always a lone '!'; this is only useful for plain
+ * scalars, where its specification means that the scalar MUST be resolved
+ * to have type tag:yaml.org,2002:str.
+ * </p>
+ *
+ * TODO SnakeYaml incorrectly ignores c-ns-non-specific-tag right now.
+ *
+ * @see <a href="http://www.yaml.org/spec/1.1/#id900262"></a>
+ *
+ * TODO Note that this method does not enforce rules about local versus
+ * global tags!
+ */
+ private Token scanTag() {
+ // See the specification for details.
+ Mark startMark = reader.getMark();
+ // Determine the type of tag property based on the first character
+ // encountered
+ char ch = reader.peek(1);
+ String handle = null;
+ String suffix = null;
+ // Verbatim tag! (c-verbatim-tag)
+ if (ch == '<') {
+ // Skip the exclamation mark and >, then read the tag suffix (as
+ // a URI).
+ reader.forward(2);
+ suffix = scanTagUri("tag", startMark);
+ if (reader.peek() != '>') {
+ // If there are any characters between the end of the tag-suffix
+ // URI and the closing >, then an error has occurred.
+ throw new ScannerException("while scanning a tag", startMark,
+ "expected '>', but found '" + reader.peek() + "' (" + ((int) reader.peek())
+ + ")", reader.getMark());
+ }
+ reader.forward();
+ } else if (Constant.NULL_BL_T_LINEBR.has(ch)) {
+ // A NUL, blank, tab, or line-break means that this was a
+ // c-ns-non-specific tag.
+ suffix = "!";
+ reader.forward();
+ } else {
+ // Any other character implies c-ns-shorthand-tag type.
+
+ // Look ahead in the stream to determine whether this tag property
+ // is of the form !foo or !foo!bar.
+ int length = 1;
+ boolean useHandle = false;
+ while (Constant.NULL_BL_LINEBR.hasNo(ch)) {
+ if (ch == '!') {
+ useHandle = true;
+ break;
+ }
+ length++;
+ ch = reader.peek(length);
+ }
+ handle = "!";
+ // If we need to use a handle, scan it in; otherwise, the handle is
+ // presumed to be '!'.
+ if (useHandle) {
+ handle = scanTagHandle("tag", startMark);
+ } else {
+ handle = "!";
+ reader.forward();
+ }
+ suffix = scanTagUri("tag", startMark);
+ }
+ ch = reader.peek();
+ // Check that the next character is allowed to follow a tag-property;
+ // if it is not, raise the error.
+ if (Constant.NULL_BL_LINEBR.hasNo(ch)) {
+ throw new ScannerException("while scanning a tag", startMark,
+ "expected ' ', but found '" + ch + "' (" + ((int) ch) + ")", reader.getMark());
+ }
+ TagTuple value = new TagTuple(handle, suffix);
+ Mark endMark = reader.getMark();
+ return new TagToken(value, startMark, endMark);
+ }
+
+ private Token scanBlockScalar(char style) {
+ // See the specification for details.
+ boolean folded;
+ // Depending on the given style, we determine whether the scalar is
+ // folded ('>') or literal ('|')
+ if (style == '>') {
+ folded = true;
+ } else {
+ folded = false;
+ }
+ StringBuilder chunks = new StringBuilder();
+ Mark startMark = reader.getMark();
+ // Scan the header.
+ reader.forward();
+ Chomping chompi = scanBlockScalarIndicators(startMark);
+ int increment = chompi.getIncrement();
+ 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 (Constant.NULL_OR_LINEBR.hasNo(reader.peek(length))) {
+ length++;
+ }
+ chunks.append(reader.prefixForward(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 && "\n".equals(lineBreak) && 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 (chompi.chompTailIsNotFalse()) {
+ chunks.append(lineBreak);
+ }
+ if (chompi.chompTailIsTrue()) {
+ chunks.append(breaks);
+ }
+ // We are done.
+ return new ScalarToken(chunks.toString(), false, startMark, endMark, style);
+ }
+
+ /**
+ * Scan a block scalar indicator. The block scalar indicator includes two
+ * optional components, which may appear in either order.
+ *
+ * A block indentation indicator is a non-zero digit describing the
+ * indentation level of the block scalar to follow. This indentation is an
+ * additional number of spaces relative to the current indentation level.
+ *
+ * A block chomping indicator is a + or -, selecting the chomping mode away
+ * from the default (clip) to either -(strip) or +(keep).
+ *
+ * @see <a href="http://www.yaml.org/spec/1.1/#id868988"></a>
+ * @see <a href="http://www.yaml.org/spec/1.1/#id927035"></a>
+ * @see <a href="http://www.yaml.org/spec/1.1/#id927557"></a>
+ */
+ private Chomping 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 (Constant.NULL_BL_LINEBR.hasNo(ch)) {
+ throw new ScannerException("while scanning a block scalar", startMark,
+ "expected chomping or indentation indicators, but found " + ch,
+ reader.getMark());
+ }
+ return new Chomping(chomping, increment);
+ }
+
+ /**
+ * Scan to the end of the line after a block scalar has been scanned; the
+ * only things that are permitted at this time are comments and spaces.
+ */
+ private String scanBlockScalarIgnoredLine(Mark startMark) {
+ // See the specification for details.
+ int ff = 0;
+ // Forward past any number of trailing spaces
+ while (reader.peek(ff) == ' ') {
+ ff++;
+ }
+ if (ff > 0) {
+ reader.forward(ff);
+ }
+ // If a comment occurs, scan to just before the end of line.
+ if (reader.peek() == '#') {
+ ff = 0;
+ while (Constant.NULL_OR_LINEBR.hasNo(reader.peek(ff))) {
+ ff++;
+ }
+ if (ff > 0) {
+ reader.forward(ff);
+ }
+ }
+ // If the next character is not a null or line break, an error has
+ // occurred.
+ char ch = reader.peek();
+ String lineBreak = scanLineBreak();
+ if (lineBreak.length() == 0 && ch != '\0') {
+ throw new ScannerException("while scanning a block scalar", startMark,
+ "expected a comment or a line break, but found " + ch, reader.getMark());
+ }
+ return lineBreak;
+ }
+
+ /**
+ * Scans for the indentation of a block scalar implicitly. This mechanism is
+ * used only if the block did not explicitly state an indentation to be
+ * used.
+ *
+ * @see <a href="http://www.yaml.org/spec/1.1/#id927035"></a>
+ */
+ private Object[] scanBlockScalarIndentation() {
+ // See the specification for details.
+ StringBuilder chunks = new StringBuilder();
+ int maxIndent = 0;
+ Mark endMark = reader.getMark();
+ // Look ahead some number of lines until the first non-blank character
+ // occurs; the determined indentation will be the maximum number of
+ // leading spaces on any of these lines.
+ while (Constant.LINEBR.has(reader.peek(), " \r")) {
+ if (reader.peek() != ' ') {
+ // If the character isn't a space, it must be some kind of
+ // line-break; scan the line break and track it.
+ chunks.append(scanLineBreak());
+ endMark = reader.getMark();
+ } else {
+ // If the character is a space, move forward to the next
+ // character; if we surpass our previous maximum for indent
+ // level, update that too.
+ reader.forward();
+ if (this.reader.getColumn() > maxIndent) {
+ maxIndent = reader.getColumn();
+ }
+ }
+ }
+ // Pass several results back together.
+ return new Object[] { chunks.toString(), maxIndent, endMark };
+ }
+
+ private Object[] scanBlockScalarBreaks(int indent) {
+ // See the specification for details.
+ StringBuilder chunks = new StringBuilder();
+ Mark endMark = reader.getMark();
+ int ff = 0;
+ int col = this.reader.getColumn();
+ // Scan for up to the expected indentation-level of spaces, then move
+ // forward past that amount.
+ while (col < indent && reader.peek(ff) == ' ') {
+ ff++;
+ col++;
+ }
+ if (ff > 0) {
+ reader.forward(ff);
+ }
+ // Consume one or more line breaks followed by any amount of spaces,
+ // until we find something that isn't a line-break.
+ String lineBreak = null;
+ while ((lineBreak = scanLineBreak()).length() != 0) {
+ chunks.append(lineBreak);
+ endMark = reader.getMark();
+ // Scan past up to (indent) spaces on the next line, then forward
+ // past them.
+ ff = 0;
+ col = this.reader.getColumn();
+ while (col < indent && reader.peek(ff) == ' ') {
+ ff++;
+ col++;
+ }
+ if (ff > 0) {
+ reader.forward(ff);
+ }
+ }
+ // Return both the assembled intervening string and the end-mark.
+ return new Object[] { chunks.toString(), endMark };
+ }
+
+ /**
+ * Scan a flow-style scalar. Flow scalars are presented in one of two forms;
+ * first, a flow scalar may be a double-quoted string; second, a flow scalar
+ * may be a single-quoted string.
+ *
+ * @see <a href="http://www.yaml.org/spec/1.1/#flow"></a> style/syntax
+ *
+ * <pre>
+ * See the specification for details.
+ * Note that we loose indentation rules for quoted scalars. Quoted
+ * scalars don't need to adhere indentation because " 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;
+ // The style will be either single- or double-quoted; we determine this
+ // by the first character in the entry (supplied)
+ if (style == '"') {
+ _double = true;
+ } else {
+ _double = false;
+ }
+ StringBuilder chunks = new StringBuilder();
+ 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);
+ }
+
+ /**
+ * Scan some number of flow-scalar non-space characters.
+ */
+ private String scanFlowScalarNonSpaces(boolean doubleQuoted, Mark startMark) {
+ // See the specification for details.
+ StringBuilder chunks = new StringBuilder();
+ while (true) {
+ // Scan through any number of characters which are not: NUL, blank,
+ // tabs, line breaks, single-quotes, double-quotes, or backslashes.
+ int length = 0;
+ while (Constant.NULL_BL_T_LINEBR.hasNo(reader.peek(length), "\'\"\\")) {
+ length++;
+ }
+ if (length != 0) {
+ chunks.append(reader.prefixForward(length));
+ }
+ // Depending on our quoting-type, the characters ', " and \ have
+ // differing meanings.
+ char ch = reader.peek();
+ if (!doubleQuoted && ch == '\'' && reader.peek(1) == '\'') {
+ chunks.append("'");
+ reader.forward(2);
+ } else if ((doubleQuoted && ch == '\'') || (!doubleQuoted && "\"\\".indexOf(ch) != -1)) {
+ chunks.append(ch);
+ reader.forward();
+ } else if (doubleQuoted && ch == '\\') {
+ reader.forward();
+ ch = reader.peek();
+ if (ESCAPE_REPLACEMENTS.containsKey(Character.valueOf(ch))) {
+ // The character is one of the single-replacement
+ // types; these are replaced with a literal character
+ // from the mapping.
+ chunks.append(ESCAPE_REPLACEMENTS.get(Character.valueOf(ch)));
+ reader.forward();
+ } else if (ESCAPE_CODES.containsKey(Character.valueOf(ch))) {
+ // The character is a multi-digit escape sequence, with
+ // length defined by the value in the ESCAPE_CODES map.
+ length = ESCAPE_CODES.get(Character.valueOf(ch)).intValue();
+ reader.forward();
+ String hex = reader.prefix(length);
+ if (NOT_HEXA.matcher(hex).find()) {
+ throw new ScannerException("while scanning a double-quoted scalar",
+ startMark, "expected escape sequence of " + length
+ + " hexadecimal numbers, but found: " + hex,
+ reader.getMark());
+ }
+ int decimal = Integer.parseInt(hex, 16);
+ String unicode = new String(Character.toChars(decimal));
+ chunks.append(unicode);
+ reader.forward(length);
+ } else if (scanLineBreak().length() != 0) {
+ 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.
+ StringBuilder chunks = new StringBuilder();
+ int length = 0;
+ // Scan through any number of whitespace (space, tab) characters,
+ // consuming them.
+ while (" \t".indexOf(reader.peek(length)) != -1) {
+ length++;
+ }
+ String whitespaces = reader.prefixForward(length);
+ char ch = reader.peek();
+ if (ch == '\0') {
+ // A flow scalar cannot end with an end-of-stream
+ throw new ScannerException("while scanning a quoted scalar", startMark,
+ "found unexpected end of stream", reader.getMark());
+ }
+ // If we encounter a line break, scan it into our assembled string...
+ String lineBreak = scanLineBreak();
+ if (lineBreak.length() != 0) {
+ String breaks = scanFlowScalarBreaks(startMark);
+ if (!"\n".equals(lineBreak)) {
+ 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.
+ StringBuilder chunks = new StringBuilder();
+ while (true) {
+ // Instead of checking indentation, we check for document
+ // separators.
+ String prefix = reader.prefix(3);
+ if (("---".equals(prefix) || "...".equals(prefix))
+ && Constant.NULL_BL_T_LINEBR.has(reader.peek(3))) {
+ throw new ScannerException("while scanning a quoted scalar", startMark,
+ "found unexpected document separator", reader.getMark());
+ }
+ // Scan past any number of spaces and tabs, ignoring them
+ while (" \t".indexOf(reader.peek()) != -1) {
+ reader.forward();
+ }
+ // If we stopped at a line break, add that; otherwise, return the
+ // assembled set of scalar breaks.
+ String lineBreak = scanLineBreak();
+ if (lineBreak.length() != 0) {
+ chunks.append(lineBreak);
+ } else {
+ return chunks.toString();
+ }
+ }
+ }
+
+ /**
+ * Scan a plain scalar.
+ *
+ * <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() {
+ StringBuilder chunks = new StringBuilder();
+ Mark startMark = reader.getMark();
+ Mark endMark = startMark;
+ int indent = this.indent + 1;
+ String spaces = "";
+ while (true) {
+ char ch;
+ int length = 0;
+ // A comment indicates the end of the scalar.
+ if (reader.peek() == '#') {
+ break;
+ }
+ while (true) {
+ ch = reader.peek(length);
+ if (Constant.NULL_BL_T_LINEBR.has(ch)
+ || (this.flowLevel == 0 && ch == ':' && Constant.NULL_BL_T_LINEBR
+ .has(reader.peek(length + 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 == ':'
+ && Constant.NULL_BL_T_LINEBR.hasNo(reader.peek(length + 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.prefixForward(length));
+ endMark = reader.getMark();
+ spaces = scanPlainSpaces();
+ // System.out.printf("spaces[%s]\n", spaces);
+ if (spaces.length() == 0 || reader.peek() == '#'
+ || (this.flowLevel == 0 && this.reader.getColumn() < indent)) {
+ break;
+ }
+ }
+ return new ScalarToken(chunks.toString(), startMark, endMark, true);
+ }
+
+ /**
+ * See the specification for details. SnakeYAML and libyaml allow tabs
+ * inside plain scalar
+ */
+ private String scanPlainSpaces() {
+ int length = 0;
+ while (reader.peek(length) == ' ' || reader.peek(length) == '\t') {
+ length++;
+ }
+ String whitespaces = reader.prefixForward(length);
+ String lineBreak = scanLineBreak();
+ if (lineBreak.length() != 0) {
+ this.allowSimpleKey = true;
+ String prefix = reader.prefix(3);
+ if ("---".equals(prefix) || "...".equals(prefix)
+ && Constant.NULL_BL_T_LINEBR.has(reader.peek(3))) {
+ return "";
+ }
+ StringBuilder breaks = new StringBuilder();
+ while (true) {
+ if (reader.peek() == ' ') {
+ reader.forward();
+ } else {
+ String lb = scanLineBreak();
+ if (lb.length() != 0) {
+ breaks.append(lb);
+ prefix = reader.prefix(3);
+ if ("---".equals(prefix) || "...".equals(prefix)
+ && Constant.NULL_BL_T_LINEBR.has(reader.peek(3))) {
+ return "";
+ }
+ } else {
+ break;
+ }
+ }
+ }
+ if (!"\n".equals(lineBreak)) {
+ return lineBreak + breaks;
+ } else if (breaks.length() == 0) {
+ return " ";
+ }
+ return breaks.toString();
+ }
+ return whitespaces;
+ }
+
+ /**
+ * <p>
+ * Scan a Tag handle. A Tag handle takes one of three forms:
+ *
+ * <pre>
+ * "!" (c-primary-tag-handle)
+ * "!!" (ns-secondary-tag-handle)
+ * "!(name)!" (c-named-tag-handle)
+ * </pre>
+ *
+ * Where (name) must be formatted as an ns-word-char.
+ * </p>
+ *
+ * @see <a href="http://www.yaml.org/spec/1.1/#c-tag-handle"></a>
+ * @see <a href="http://www.yaml.org/spec/1.1/#ns-word-char"></a>
+ *
+ * <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());
+ }
+ // Look for the next '!' in the stream, stopping if we hit a
+ // non-word-character. If the first character is a space, then the
+ // tag-handle is a c-primary-tag-handle ('!').
+ int length = 1;
+ ch = reader.peek(length);
+ if (ch != ' ') {
+ // Scan through 0+ alphabetic characters.
+ // FIXME According to the specification, these should be
+ // ns-word-char only, which prohibits '_'. This might be a
+ // candidate for a configuration option.
+ while (Constant.ALPHA.has(ch)) {
+ length++;
+ ch = reader.peek(length);
+ }
+ // Found the next non-word-char. If this is not a space and not an
+ // '!', then this is an error, as the tag-handle was specified as:
+ // !(name) or similar; the trailing '!' is missing.
+ 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.prefixForward(length);
+ return value;
+ }
+
+ /**
+ * <p>
+ * Scan a Tag URI. This scanning is valid for both local and global tag
+ * directives, because both appear to be valid URIs as far as scanning is
+ * concerned. The difference may be distinguished later, in parsing. This
+ * method will scan for ns-uri-char*, which covers both cases.
+ * </p>
+ *
+ * <p>
+ * This method performs no verification that the scanned URI conforms to any
+ * particular kind of URI specification.
+ * </p>
+ *
+ * @see <a href="http://www.yaml.org/spec/1.1/#ns-uri-char"></a>
+ */
+ private String scanTagUri(String name, Mark startMark) {
+ // See the specification for details.
+ // Note: we do not check if URI is well-formed.
+ StringBuilder chunks = new StringBuilder();
+ // Scan through accepted URI characters, which includes the standard
+ // URI characters, plus the start-escape character ('%'). When we get
+ // to a start-escape, scan the escaped sequence, then return.
+ int length = 0;
+ char ch = reader.peek(length);
+ while (Constant.URI_CHARS.has(ch)) {
+ if (ch == '%') {
+ chunks.append(reader.prefixForward(length));
+ length = 0;
+ chunks.append(scanUriEscapes(name, startMark));
+ } else {
+ length++;
+ }
+ ch = reader.peek(length);
+ }
+ // Consume the last "chunk", which would not otherwise be consumed by
+ // the loop above.
+ if (length != 0) {
+ chunks.append(reader.prefixForward(length));
+ length = 0;
+ }
+ if (chunks.length() == 0) {
+ // If no URI was found, an error has occurred.
+ throw new ScannerException("while scanning a " + name, startMark,
+ "expected URI, but found " + ch + "(" + ((int) ch) + ")", reader.getMark());
+ }
+ return chunks.toString();
+ }
+
+ /**
+ * <p>
+ * Scan a sequence of %-escaped URI escape codes and convert them into a
+ * String representing the unescaped values.
+ * </p>
+ *
+ * FIXME This method fails for more than 256 bytes' worth of URI-encoded
+ * characters in a row. Is this possible? Is this a use-case?
+ *
+ * @see <a href="http://www.ietf.org/rfc/rfc2396.txt"></a>, section 2.4, Escaped Encoding.
+ */
+ private String scanUriEscapes(String name, Mark startMark) {
+ // First, look ahead to see how many URI-escaped characters we should
+ // expect, so we can use the correct buffer size.
+ int length = 1;
+ while (reader.peek(length * 3) == '%') {
+ length++;
+ }
+ // See the specification for details.
+ // URIs containing 16 and 32 bit Unicode characters are
+ // encoded in UTF-8, and then each octet is written as a
+ // separate character.
+ Mark beginningMark = reader.getMark();
+ ByteBuffer buff = ByteBuffer.allocate(length);
+ while (reader.peek() == '%') {
+ reader.forward();
+ try {
+ byte code = (byte) Integer.parseInt(reader.prefix(2), 16);
+ buff.put(code);
+ } catch (NumberFormatException nfe) {
+ throw new ScannerException("while scanning a " + name, startMark,
+ "expected URI escape sequence of 2 hexadecimal numbers, but found "
+ + reader.peek() + "(" + ((int) reader.peek()) + ") and "
+ + reader.peek(1) + "(" + ((int) reader.peek(1)) + ")",
+ reader.getMark());
+ }
+ reader.forward(2);
+ }
+ buff.flip();
+ try {
+ return UriEncoder.decode(buff);
+ } catch (CharacterCodingException e) {
+ throw new ScannerException("while scanning a " + name, startMark,
+ "expected URI in UTF-8: " + e.getMessage(), beginningMark);
+ }
+ }
+
+ /**
+ * Scan a line break, transforming:
+ *
+ * <pre>
+ * '\r\n' : '\n'
+ * '\r' : '\n'
+ * '\n' : '\n'
+ * '\x85' : '\n'
+ * default : ''
+ * </pre>
+ */
+ private String scanLineBreak() {
+ // Transforms:
+ // '\r\n' : '\n'
+ // '\r' : '\n'
+ // '\n' : '\n'
+ // '\x85' : '\n'
+ // default : ''
+ char ch = reader.peek();
+ if (ch == '\r' || ch == '\n' || ch == '\u0085') {
+ if (ch == '\r' && '\n' == reader.peek(1)) {
+ reader.forward(2);
+ } else {
+ reader.forward();
+ }
+ return "\n";
+ } else if (ch == '\u2028' || ch == '\u2029') {
+ reader.forward();
+ return String.valueOf(ch);
+ }
+ return "";
+ }
+
+ /**
+ * Chomping the tail may have 3 values - yes, no, not defined.
+ */
+ private static class Chomping {
+ private final Boolean value;
+ private final int increment;
+
+ public Chomping(Boolean value, int increment) {
+ this.value = value;
+ this.increment = increment;
+ }
+
+ public boolean chompTailIsNotFalse() {
+ return value == null || value;
+ }
+
+ public boolean chompTailIsTrue() {
+ return value != null && value;
+ }
+
+ public int getIncrement() {
+ return increment;
+ }
+ }
+}
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 0000000..3fe710c
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/scanner/SimpleKey.java
@@ -0,0 +1,74 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.scanner;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * Simple keys treatment.
+ * <p>
+ * Helper class for {@link ScannerImpl}.
+ * </p>
+ *
+ * @see ScannerImpl
+ */
+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/AnchorGenerator.java b/src/main/java/org/yaml/snakeyaml/serializer/AnchorGenerator.java
new file mode 100644
index 0000000..2308eb5
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/serializer/AnchorGenerator.java
@@ -0,0 +1,23 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.serializer;
+
+import org.yaml.snakeyaml.nodes.Node;
+
+public interface AnchorGenerator {
+
+ String nextAnchor(Node node);
+}
diff --git a/src/main/java/org/yaml/snakeyaml/serializer/NumberAnchorGenerator.java b/src/main/java/org/yaml/snakeyaml/serializer/NumberAnchorGenerator.java
new file mode 100644
index 0000000..2f316f8
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/serializer/NumberAnchorGenerator.java
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.serializer;
+
+import org.yaml.snakeyaml.nodes.Node;
+
+import java.text.NumberFormat;
+
+public class NumberAnchorGenerator implements AnchorGenerator {
+
+ private int lastAnchorId = 0;
+
+ public NumberAnchorGenerator(int lastAnchorId) {
+ this.lastAnchorId = lastAnchorId;
+ }
+
+ public String nextAnchor(Node node) {
+ this.lastAnchorId++;
+ NumberFormat format = NumberFormat.getNumberInstance();
+ format.setMinimumIntegerDigits(3);
+ format.setMaximumFractionDigits(0);// issue 172
+ format.setGroupingUsed(false);
+ String anchorId = format.format(this.lastAnchorId);
+ return "id" + anchorId;
+ }
+}
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 0000000..2decf3f
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/serializer/Serializer.java
@@ -0,0 +1,201 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+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.DumperOptions.Version;
+import org.yaml.snakeyaml.emitter.Emitable;
+import org.yaml.snakeyaml.events.AliasEvent;
+import org.yaml.snakeyaml.events.DocumentEndEvent;
+import org.yaml.snakeyaml.events.DocumentStartEvent;
+import org.yaml.snakeyaml.events.ImplicitTuple;
+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.AnchorNode;
+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.NodeTuple;
+import org.yaml.snakeyaml.nodes.ScalarNode;
+import org.yaml.snakeyaml.nodes.SequenceNode;
+import org.yaml.snakeyaml.nodes.Tag;
+import org.yaml.snakeyaml.resolver.Resolver;
+
+public final class Serializer {
+ private final Emitable emitter;
+ private final Resolver resolver;
+ private boolean explicitStart;
+ private boolean explicitEnd;
+ private Version useVersion;
+ private Map<String, String> useTags;
+ private Set<Node> serializedNodes;
+ private Map<Node, String> anchors;
+ private AnchorGenerator anchorGenerator;
+ private Boolean closed;
+ private Tag explicitRoot;
+
+ public Serializer(Emitable emitter, Resolver resolver, DumperOptions opts, Tag rootTag) {
+ this.emitter = emitter;
+ this.resolver = resolver;
+ this.explicitStart = opts.isExplicitStart();
+ this.explicitEnd = opts.isExplicitEnd();
+ if (opts.getVersion() != null) {
+ this.useVersion = opts.getVersion();
+ }
+ this.useTags = opts.getTags();
+ this.serializedNodes = new HashSet<Node>();
+ this.anchors = new HashMap<Node, String>();
+ this.anchorGenerator = opts.getAnchorGenerator();
+ this.closed = null;
+ this.explicitRoot = rootTag;
+ }
+
+ 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);
+ this.emitter.emit(new DocumentEndEvent(null, null, this.explicitEnd));
+ this.serializedNodes.clear();
+ this.anchors.clear();
+ }
+
+ private void anchorNode(Node node) {
+ if (node.getNodeId() == NodeId.anchor) {
+ node = ((AnchorNode) node).getRealNode();
+ }
+ if (this.anchors.containsKey(node)) {
+ String anchor = this.anchors.get(node);
+ if (null == anchor) {
+ anchor = this.anchorGenerator.nextAnchor(node);
+ this.anchors.put(node, anchor);
+ }
+ } else {
+ this.anchors.put(node, null);
+ switch (node.getNodeId()) {
+ case sequence:
+ SequenceNode seqNode = (SequenceNode) node;
+ List<Node> list = seqNode.getValue();
+ for (Node item : list) {
+ anchorNode(item);
+ }
+ break;
+ case mapping:
+ MappingNode mnode = (MappingNode) node;
+ List<NodeTuple> map = mnode.getValue();
+ for (NodeTuple object : map) {
+ Node key = object.getKeyNode();
+ Node value = object.getValueNode();
+ anchorNode(key);
+ anchorNode(value);
+ }
+ break;
+ }
+ }
+ }
+
+ private void serializeNode(Node node, Node parent) throws IOException {
+ if (node.getNodeId() == NodeId.anchor) {
+ node = ((AnchorNode) node).getRealNode();
+ }
+ String tAlias = this.anchors.get(node);
+ if (this.serializedNodes.contains(node)) {
+ this.emitter.emit(new AliasEvent(tAlias, null, null));
+ } else {
+ this.serializedNodes.add(node);
+ switch (node.getNodeId()) {
+ case scalar:
+ ScalarNode scalarNode = (ScalarNode) node;
+ Tag detectedTag = this.resolver.resolve(NodeId.scalar, scalarNode.getValue(), true);
+ Tag defaultTag = this.resolver.resolve(NodeId.scalar, scalarNode.getValue(), false);
+ ImplicitTuple tuple = new ImplicitTuple(node.getTag().equals(detectedTag), node
+ .getTag().equals(defaultTag));
+ ScalarEvent event = new ScalarEvent(tAlias, node.getTag().getValue(), tuple,
+ scalarNode.getValue(), null, null, scalarNode.getStyle());
+ this.emitter.emit(event);
+ break;
+ case sequence:
+ SequenceNode seqNode = (SequenceNode) node;
+ boolean implicitS = node.getTag().equals(this.resolver.resolve(NodeId.sequence,
+ null, true));
+ this.emitter.emit(new SequenceStartEvent(tAlias, node.getTag().getValue(),
+ implicitS, null, null, seqNode.getFlowStyle()));
+ List<Node> list = seqNode.getValue();
+ for (Node item : list) {
+ serializeNode(item, node);
+ }
+ this.emitter.emit(new SequenceEndEvent(null, null));
+ break;
+ default:// instance of MappingNode
+ Tag implicitTag = this.resolver.resolve(NodeId.mapping, null, true);
+ boolean implicitM = node.getTag().equals(implicitTag);
+ this.emitter.emit(new MappingStartEvent(tAlias, node.getTag().getValue(),
+ implicitM, null, null, ((CollectionNode) node).getFlowStyle()));
+ MappingNode mnode = (MappingNode) node;
+ List<NodeTuple> map = mnode.getValue();
+ for (NodeTuple row : map) {
+ Node key = row.getKeyNode();
+ Node value = row.getValueNode();
+ serializeNode(key, mnode);
+ serializeNode(value, mnode);
+ }
+ 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 0000000..0cb6e88
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/serializer/SerializerException.java
@@ -0,0 +1,26 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.serializer;
+
+import org.yaml.snakeyaml.error.YAMLException;
+
+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 0000000..df2ee2e
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/tokens/AliasToken.java
@@ -0,0 +1,41 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import org.yaml.snakeyaml.error.Mark;
+
+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 Token.ID getTokenId() {
+ return ID.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 0000000..3629eea
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/tokens/AnchorToken.java
@@ -0,0 +1,41 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import org.yaml.snakeyaml.error.Mark;
+
+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 Token.ID getTokenId() {
+ return ID.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 0000000..3315bc4
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/tokens/BlockEndToken.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import org.yaml.snakeyaml.error.Mark;
+
+public final class BlockEndToken extends Token {
+
+ public BlockEndToken(Mark startMark, Mark endMark) {
+ super(startMark, endMark);
+ }
+
+ @Override
+ public Token.ID getTokenId() {
+ return ID.BlockEnd;
+ }
+}
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 0000000..574445f
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/tokens/BlockEntryToken.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import org.yaml.snakeyaml.error.Mark;
+
+public final class BlockEntryToken extends Token {
+
+ public BlockEntryToken(Mark startMark, Mark endMark) {
+ super(startMark, endMark);
+ }
+
+ @Override
+ public Token.ID getTokenId() {
+ return ID.BlockEntry;
+ }
+}
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 0000000..95a6164
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/tokens/BlockMappingStartToken.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import org.yaml.snakeyaml.error.Mark;
+
+public final class BlockMappingStartToken extends Token {
+
+ public BlockMappingStartToken(Mark startMark, Mark endMark) {
+ super(startMark, endMark);
+ }
+
+ @Override
+ public Token.ID getTokenId() {
+ return ID.BlockMappingStart;
+ }
+}
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 0000000..d70194c
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/tokens/BlockSequenceStartToken.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import org.yaml.snakeyaml.error.Mark;
+
+public final class BlockSequenceStartToken extends Token {
+
+ public BlockSequenceStartToken(Mark startMark, Mark endMark) {
+ super(startMark, endMark);
+ }
+
+ @Override
+ public Token.ID getTokenId() {
+ return ID.BlockSequenceStart;
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/tokens/CommentToken.java b/src/main/java/org/yaml/snakeyaml/tokens/CommentToken.java
new file mode 100644
index 0000000..12c067e
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/tokens/CommentToken.java
@@ -0,0 +1,29 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import org.yaml.snakeyaml.error.Mark;
+
+public class CommentToken extends Token {
+ public CommentToken(Mark startMark, Mark endMark) {
+ super(startMark, endMark);
+ }
+
+ @Override
+ public ID getTokenId() {
+ return ID.Comment;
+ }
+}
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 0000000..af1743f
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/tokens/DirectiveToken.java
@@ -0,0 +1,58 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import java.util.List;
+
+import org.yaml.snakeyaml.error.Mark;
+import org.yaml.snakeyaml.error.YAMLException;
+
+public final class DirectiveToken<T> extends Token {
+ private final String name;
+ private final List<T> value;
+
+ public DirectiveToken(String name, List<T> 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<T> 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 Token.ID getTokenId() {
+ return ID.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 0000000..ee17dab
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/tokens/DocumentEndToken.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import org.yaml.snakeyaml.error.Mark;
+
+public final class DocumentEndToken extends Token {
+
+ public DocumentEndToken(Mark startMark, Mark endMark) {
+ super(startMark, endMark);
+ }
+
+ @Override
+ public Token.ID getTokenId() {
+ return ID.DocumentEnd;
+ }
+}
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 0000000..0b72deb
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/tokens/DocumentStartToken.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import org.yaml.snakeyaml.error.Mark;
+
+public final class DocumentStartToken extends Token {
+
+ public DocumentStartToken(Mark startMark, Mark endMark) {
+ super(startMark, endMark);
+ }
+
+ @Override
+ public Token.ID getTokenId() {
+ return ID.DocumentStart;
+ }
+}
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 0000000..b1afb0f
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/tokens/FlowEntryToken.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import org.yaml.snakeyaml.error.Mark;
+
+public final class FlowEntryToken extends Token {
+
+ public FlowEntryToken(Mark startMark, Mark endMark) {
+ super(startMark, endMark);
+ }
+
+ @Override
+ public Token.ID getTokenId() {
+ return ID.FlowEntry;
+ }
+}
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 0000000..1659a9f
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/tokens/FlowMappingEndToken.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import org.yaml.snakeyaml.error.Mark;
+
+public final class FlowMappingEndToken extends Token {
+
+ public FlowMappingEndToken(Mark startMark, Mark endMark) {
+ super(startMark, endMark);
+ }
+
+ @Override
+ public Token.ID getTokenId() {
+ return ID.FlowMappingEnd;
+ }
+}
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 0000000..5a984c7
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/tokens/FlowMappingStartToken.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import org.yaml.snakeyaml.error.Mark;
+
+public final class FlowMappingStartToken extends Token {
+
+ public FlowMappingStartToken(Mark startMark, Mark endMark) {
+ super(startMark, endMark);
+ }
+
+ @Override
+ public Token.ID getTokenId() {
+ return ID.FlowMappingStart;
+ }
+}
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 0000000..39b03c4
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/tokens/FlowSequenceEndToken.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import org.yaml.snakeyaml.error.Mark;
+
+public final class FlowSequenceEndToken extends Token {
+
+ public FlowSequenceEndToken(Mark startMark, Mark endMark) {
+ super(startMark, endMark);
+ }
+
+ @Override
+ public Token.ID getTokenId() {
+ return ID.FlowSequenceEnd;
+ }
+}
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 0000000..da89785
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/tokens/FlowSequenceStartToken.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import org.yaml.snakeyaml.error.Mark;
+
+public final class FlowSequenceStartToken extends Token {
+
+ public FlowSequenceStartToken(Mark startMark, Mark endMark) {
+ super(startMark, endMark);
+ }
+
+ @Override
+ public Token.ID getTokenId() {
+ return ID.FlowSequenceStart;
+ }
+}
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 0000000..0f88043
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/tokens/KeyToken.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import org.yaml.snakeyaml.error.Mark;
+
+public final class KeyToken extends Token {
+
+ public KeyToken(Mark startMark, Mark endMark) {
+ super(startMark, endMark);
+ }
+
+ @Override
+ public Token.ID getTokenId() {
+ return ID.Key;
+ }
+}
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 0000000..828189e
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/tokens/ScalarToken.java
@@ -0,0 +1,57 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import org.yaml.snakeyaml.error.Mark;
+
+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 Token.ID getTokenId() {
+ return ID.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 0000000..ece87b9
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/tokens/StreamEndToken.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import org.yaml.snakeyaml.error.Mark;
+
+public final class StreamEndToken extends Token {
+
+ public StreamEndToken(Mark startMark, Mark endMark) {
+ super(startMark, endMark);
+ }
+
+ @Override
+ public Token.ID getTokenId() {
+ return ID.StreamEnd;
+ }
+}
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 0000000..4b5419a
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/tokens/StreamStartToken.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import org.yaml.snakeyaml.error.Mark;
+
+public final class StreamStartToken extends Token {
+
+ public StreamStartToken(Mark startMark, Mark endMark) {
+ super(startMark, endMark);
+ }
+
+ @Override
+ public Token.ID getTokenId() {
+ return ID.StreamStart;
+ }
+}
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 0000000..505a360
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/tokens/TagToken.java
@@ -0,0 +1,41 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import org.yaml.snakeyaml.error.Mark;
+
+public final class TagToken extends Token {
+ private final TagTuple value;
+
+ public TagToken(TagTuple value, Mark startMark, Mark endMark) {
+ super(startMark, endMark);
+ this.value = value;
+ }
+
+ public TagTuple getValue() {
+ return this.value;
+ }
+
+ @Override
+ protected String getArguments() {
+ return "value=[" + value.getHandle() + ", " + value.getSuffix() + "]";
+ }
+
+ @Override
+ public Token.ID getTokenId() {
+ return ID.Tag;
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/tokens/TagTuple.java b/src/main/java/org/yaml/snakeyaml/tokens/TagTuple.java
new file mode 100644
index 0000000..b4ea064
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/tokens/TagTuple.java
@@ -0,0 +1,37 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.tokens;
+
+public final class TagTuple {
+ private final String handle;
+ private final String suffix;
+
+ public TagTuple(String handle, String suffix) {
+ if (suffix == null) {
+ throw new NullPointerException("Suffix must be provided.");
+ }
+ this.handle = handle;
+ this.suffix = suffix;
+ }
+
+ public String getHandle() {
+ return handle;
+ }
+
+ public String getSuffix() {
+ return suffix;
+ }
+}
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 0000000..8b583f5
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/tokens/Token.java
@@ -0,0 +1,82 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import org.yaml.snakeyaml.error.Mark;
+import org.yaml.snakeyaml.error.YAMLException;
+
+public abstract class Token {
+ public enum ID {
+ Alias, Anchor, BlockEnd, BlockEntry, BlockMappingStart, BlockSequenceStart, Directive, DocumentEnd, DocumentStart, FlowEntry, FlowMappingEnd, FlowMappingStart, FlowSequenceEnd, FlowSequenceStart, Key, Scalar, StreamEnd, StreamStart, Tag, Value, Whitespace, Comment, Error
+ }
+
+ private final Mark startMark;
+ private final Mark endMark;
+
+ public Token(Mark startMark, Mark endMark) {
+ if (startMark == null || endMark == null) {
+ throw new YAMLException("Token requires marks.");
+ }
+ 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 Token.ID getTokenId();
+
+ /*
+ * for tests only
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof Token) {
+ return toString().equals(obj.toString());
+ } else {
+ return false;
+ }
+ }
+
+ /*
+ * for tests only
+ */
+ @Override
+ public int hashCode() {
+ return toString().hashCode();
+ }
+}
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 0000000..58fe057
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/tokens/ValueToken.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import org.yaml.snakeyaml.error.Mark;
+
+public final class ValueToken extends Token {
+
+ public ValueToken(Mark startMark, Mark endMark) {
+ super(startMark, endMark);
+ }
+
+ @Override
+ public Token.ID getTokenId() {
+ return ID.Value;
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/tokens/WhitespaceToken.java b/src/main/java/org/yaml/snakeyaml/tokens/WhitespaceToken.java
new file mode 100644
index 0000000..65af212
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/tokens/WhitespaceToken.java
@@ -0,0 +1,29 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import org.yaml.snakeyaml.error.Mark;
+
+public class WhitespaceToken extends Token {
+ public WhitespaceToken(Mark startMark, Mark endMark) {
+ super(startMark, endMark);
+ }
+
+ @Override
+ public ID getTokenId() {
+ return ID.Whitespace;
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/util/ArrayStack.java b/src/main/java/org/yaml/snakeyaml/util/ArrayStack.java
new file mode 100644
index 0000000..4bab182
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/util/ArrayStack.java
@@ -0,0 +1,42 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.util;
+
+import java.util.ArrayList;
+
+public class ArrayStack<T> {
+ private ArrayList<T> stack;
+
+ public ArrayStack(int initSize) {
+ stack = new ArrayList<T>(initSize);
+ }
+
+ public void push(T obj) {
+ stack.add(obj);
+ }
+
+ public T pop() {
+ return stack.remove(stack.size() - 1);
+ }
+
+ public boolean isEmpty() {
+ return stack.isEmpty();
+ }
+
+ public void clear() {
+ stack.clear();
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/util/UriEncoder.java b/src/main/java/org/yaml/snakeyaml/util/UriEncoder.java
new file mode 100644
index 0000000..e23904f
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/util/UriEncoder.java
@@ -0,0 +1,62 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.util;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CodingErrorAction;
+
+import org.yaml.snakeyaml.error.YAMLException;
+import org.yaml.snakeyaml.external.com.google.gdata.util.common.base.Escaper;
+import org.yaml.snakeyaml.external.com.google.gdata.util.common.base.PercentEscaper;
+
+public abstract class UriEncoder {
+ private static final CharsetDecoder UTF8Decoder = Charset.forName("UTF-8").newDecoder()
+ .onMalformedInput(CodingErrorAction.REPORT);
+ // Include the [] chars to the SAFEPATHCHARS_URLENCODER to avoid
+ // its escape as required by spec. See
+ // http://yaml.org/spec/1.1/#escaping%20in%20URI/
+ private static final String SAFE_CHARS = PercentEscaper.SAFEPATHCHARS_URLENCODER + "[]/";
+ private static final Escaper escaper = new PercentEscaper(SAFE_CHARS, false);
+
+ /**
+ * Escape special characters with '%'
+ */
+ public static String encode(String uri) {
+ return escaper.escape(uri);
+ }
+
+ /**
+ * Decode '%'-escaped characters. Decoding fails in case of invalid UTF-8
+ */
+ public static String decode(ByteBuffer buff) throws CharacterCodingException {
+ CharBuffer chars = UTF8Decoder.decode(buff);
+ return chars.toString();
+ }
+
+ public static String decode(String buff) {
+ try {
+ return URLDecoder.decode(buff, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw new YAMLException(e);
+ }
+ }
+}
diff --git a/src/patches/android/CompactConstructor.patch b/src/patches/android/CompactConstructor.patch
new file mode 100644
index 0000000..c935ecd
--- /dev/null
+++ b/src/patches/android/CompactConstructor.patch
@@ -0,0 +1,22 @@
+# HG changeset patch
+# Parent 802af3ea9a2228c074259858b737e2cda0d22a7c
+diff --git a/src/main/java/org/yaml/snakeyaml/extensions/compactnotation/CompactConstructor.java b/src/main/java/org/yaml/snakeyaml/extensions/compactnotation/CompactConstructor.java
+--- a/src/main/java/org/yaml/snakeyaml/extensions/compactnotation/CompactConstructor.java
++++ b/src/main/java/org/yaml/snakeyaml/extensions/compactnotation/CompactConstructor.java
+@@ -15,7 +15,6 @@
+ */
+ package org.yaml.snakeyaml.extensions.compactnotation;
+
+-import java.beans.IntrospectionException;
+ import java.util.HashMap;
+ import java.util.Iterator;
+ import java.util.List;
+@@ -186,7 +185,7 @@
+ *
+ * @throws IntrospectionException
+ */
+- protected String getSequencePropertyName(Class<?> bean) throws IntrospectionException {
++ protected String getSequencePropertyName(Class<?> bean) {
+ Set<Property> properties = getPropertyUtils().getProperties(bean);
+ for (Iterator<Property> iterator = properties.iterator(); iterator.hasNext();) {
+ Property property = iterator.next();
diff --git a/src/patches/android/Constructor.patch b/src/patches/android/Constructor.patch
new file mode 100644
index 0000000..1588666
--- /dev/null
+++ b/src/patches/android/Constructor.patch
@@ -0,0 +1,24 @@
+# HG changeset patch
+# Parent 6211618dbbb85e16ccdfea2c1c68e098ac1bc333
+
+diff --git a/src/main/java/org/yaml/snakeyaml/constructor/Constructor.java b/src/main/java/org/yaml/snakeyaml/constructor/Constructor.java
+--- a/src/main/java/org/yaml/snakeyaml/constructor/Constructor.java
++++ b/src/main/java/org/yaml/snakeyaml/constructor/Constructor.java
+@@ -15,7 +15,6 @@
+ */
+ package org.yaml.snakeyaml.constructor;
+
+-import java.beans.IntrospectionException;
+ import java.math.BigDecimal;
+ import java.math.BigInteger;
+ import java.util.ArrayList;
+@@ -303,8 +302,7 @@
+ return object;
+ }
+
+- protected Property getProperty(Class<? extends Object> type, String name)
+- throws IntrospectionException {
++ protected Property getProperty(Class<? extends Object> type, String name) {
+ return getPropertyUtils().getProperty(type, name);
+ }
+ }
diff --git a/src/patches/android/PropertyUtils.patch b/src/patches/android/PropertyUtils.patch
new file mode 100644
index 0000000..dc72ef3
--- /dev/null
+++ b/src/patches/android/PropertyUtils.patch
@@ -0,0 +1,118 @@
+# HG changeset patch
+# Parent 698e9f1d6348fc1066ceaac7d264cbbf63bdcd21
+diff --git a/src/main/java/org/yaml/snakeyaml/introspector/PropertyUtils.java b/src/main/java/org/yaml/snakeyaml/introspector/PropertyUtils.java
+--- a/src/main/java/org/yaml/snakeyaml/introspector/PropertyUtils.java
++++ b/src/main/java/org/yaml/snakeyaml/introspector/PropertyUtils.java
+@@ -15,11 +15,7 @@
+ */
+ package org.yaml.snakeyaml.introspector;
+
+-import java.beans.IntrospectionException;
+-import java.beans.Introspector;
+-import java.beans.PropertyDescriptor;
+ import java.lang.reflect.Field;
+-import java.lang.reflect.Method;
+ import java.lang.reflect.Modifier;
+ import java.util.Collection;
+ import java.util.HashMap;
+@@ -37,64 +33,31 @@
+ private BeanAccess beanAccess = BeanAccess.DEFAULT;
+ private boolean allowReadOnlyProperties = false;
+
+- protected Map<String, Property> getPropertiesMap(Class<?> type, BeanAccess bAccess)
+- throws IntrospectionException {
++ protected Map<String, Property> getPropertiesMap(Class<?> type, BeanAccess bAccess) {
+ if (propertiesCache.containsKey(type)) {
+ return propertiesCache.get(type);
+ }
+
+ Map<String, Property> properties = new LinkedHashMap<String, Property>();
+- boolean inaccessableFieldsExist = false;
+- switch (bAccess) {
+- case FIELD:
+- for (Class<?> c = type; c != null; c = c.getSuperclass()) {
+- for (Field field : c.getDeclaredFields()) {
+- int modifiers = field.getModifiers();
+- if (!Modifier.isStatic(modifiers) && !Modifier.isTransient(modifiers)
+- && !properties.containsKey(field.getName())) {
+- properties.put(field.getName(), new FieldProperty(field));
+- }
++ for (Class<?> c = type; c != null; c = c.getSuperclass()) {
++ for (Field field : c.getDeclaredFields()) {
++ int modifiers = field.getModifiers();
++ if (!Modifier.isStatic(modifiers) && !Modifier.isTransient(modifiers)
++ && !properties.containsKey(field.getName())) {
++ properties.put(field.getName(), new FieldProperty(field));
+ }
+ }
+- break;
+- default:
+- // add JavaBean properties
+- for (PropertyDescriptor property : Introspector.getBeanInfo(type)
+- .getPropertyDescriptors()) {
+- Method readMethod = property.getReadMethod();
+- if (readMethod == null || !readMethod.getName().equals("getClass")) {
+- properties.put(property.getName(), new MethodProperty(property));
+- }
+- }
++ }
+
+- // add public fields
+- for (Class<?> c = type; c != null; c = c.getSuperclass()) {
+- for (Field field : c.getDeclaredFields()) {
+- int modifiers = field.getModifiers();
+- if (!Modifier.isStatic(modifiers) && !Modifier.isTransient(modifiers)) {
+- if (Modifier.isPublic(modifiers)) {
+- properties.put(field.getName(), new FieldProperty(field));
+- } else {
+- inaccessableFieldsExist = true;
+- }
+- }
+- }
+- }
+- break;
+- }
+- if (properties.isEmpty() && inaccessableFieldsExist) {
+- throw new YAMLException("No JavaBean properties found in " + type.getName());
+- }
+ propertiesCache.put(type, properties);
+ return properties;
+ }
+
+- public Set<Property> getProperties(Class<? extends Object> type) throws IntrospectionException {
++ public Set<Property> getProperties(Class<? extends Object> type) {
+ return getProperties(type, beanAccess);
+ }
+
+- public Set<Property> getProperties(Class<? extends Object> type, BeanAccess bAccess)
+- throws IntrospectionException {
++ public Set<Property> getProperties(Class<? extends Object> type, BeanAccess bAccess) {
+ if (readableProperties.containsKey(type)) {
+ return readableProperties.get(type);
+ }
+@@ -103,8 +66,7 @@
+ return properties;
+ }
+
+- protected Set<Property> createPropertySet(Class<? extends Object> type, BeanAccess bAccess)
+- throws IntrospectionException {
++ protected Set<Property> createPropertySet(Class<? extends Object> type, BeanAccess bAccess) {
+ Set<Property> properties = new TreeSet<Property>();
+ Collection<Property> props = getPropertiesMap(type, bAccess).values();
+ for (Property property : props) {
+@@ -115,13 +77,11 @@
+ return properties;
+ }
+
+- public Property getProperty(Class<? extends Object> type, String name)
+- throws IntrospectionException {
++ public Property getProperty(Class<? extends Object> type, String name) {
+ return getProperty(type, name, beanAccess);
+ }
+
+- public Property getProperty(Class<? extends Object> type, String name, BeanAccess bAccess)
+- throws IntrospectionException {
++ public Property getProperty(Class<? extends Object> type, String name, BeanAccess bAccess) {
+ Map<String, Property> properties = getPropertiesMap(type, bAccess);
+ Property property = properties.get(name);
+ if (property == null || !property.isWritable()) {
diff --git a/src/patches/android/Representer.patch b/src/patches/android/Representer.patch
new file mode 100644
index 0000000..187853e
--- /dev/null
+++ b/src/patches/android/Representer.patch
@@ -0,0 +1,44 @@
+# HG changeset patch
+# Parent 44449b0d7ff73bbda13c28f2ebd4e8257c67a181
+diff --git a/src/main/java/org/yaml/snakeyaml/representer/Representer.java b/src/main/java/org/yaml/snakeyaml/representer/Representer.java
+--- a/src/main/java/org/yaml/snakeyaml/representer/Representer.java
++++ b/src/main/java/org/yaml/snakeyaml/representer/Representer.java
+@@ -15,7 +15,6 @@
+ */
+ package org.yaml.snakeyaml.representer;
+
+-import java.beans.IntrospectionException;
+ import java.util.ArrayList;
+ import java.util.Arrays;
+ import java.util.Iterator;
+@@ -24,7 +23,6 @@
+ import java.util.Set;
+
+ import org.yaml.snakeyaml.DumperOptions.FlowStyle;
+-import org.yaml.snakeyaml.error.YAMLException;
+ import org.yaml.snakeyaml.introspector.Property;
+ import org.yaml.snakeyaml.nodes.MappingNode;
+ import org.yaml.snakeyaml.nodes.Node;
+@@ -45,11 +43,7 @@
+
+ protected class RepresentJavaBean implements Represent {
+ public Node representData(Object data) {
+- try {
+- return representJavaBean(getProperties(data.getClass()), data);
+- } catch (IntrospectionException e) {
+- throw new YAMLException(e);
+- }
++ return representJavaBean(getProperties(data.getClass()), data);
+ }
+ }
+
+@@ -233,8 +227,7 @@
+ * - JavaBean to inspect the properties
+ * @return properties to serialise
+ */
+- protected Set<Property> getProperties(Class<? extends Object> type)
+- throws IntrospectionException {
++ protected Set<Property> getProperties(Class<? extends Object> type) {
+ return getPropertyUtils().getProperties(type);
+ }
+ }
diff --git a/src/test/java/biz/source_code/base64Coder/Base64CoderTest.java b/src/test/java/biz/source_code/base64Coder/Base64CoderTest.java
new file mode 100644
index 0000000..60f6d84
--- /dev/null
+++ b/src/test/java/biz/source_code/base64Coder/Base64CoderTest.java
@@ -0,0 +1,73 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package biz.source_code.base64Coder;
+
+import java.io.UnsupportedEncodingException;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder;
+
+public class Base64CoderTest extends TestCase {
+
+ public void testDecode() throws UnsupportedEncodingException {
+ check("Aladdin:open sesame", "QWxhZGRpbjpvcGVuIHNlc2FtZQ==");
+ check("a", "YQ==");
+ check("aa", "YWE=");
+ check("a=", "YT0=");
+ check("", "");
+ }
+
+ public void testFailure1() throws UnsupportedEncodingException {
+ try {
+ Base64Coder.decode("YQ=".toCharArray());
+ fail();
+ } catch (Exception e) {
+ assertEquals("Length of Base64 encoded input string is not a multiple of 4.",
+ e.getMessage());
+ }
+ }
+
+ public void testFailure2() throws UnsupportedEncodingException {
+ checkInvalid("\tWE=");
+ checkInvalid("Y\tE=");
+ checkInvalid("YW\t=");
+ checkInvalid("YWE\t");
+ //
+ checkInvalid("©WE=");
+ checkInvalid("Y©E=");
+ checkInvalid("YW©=");
+ checkInvalid("YWE©");
+ }
+
+ private void checkInvalid(String encoded) {
+ try {
+ Base64Coder.decode(encoded.toCharArray());
+ fail("Illegal chanracter.");
+ } catch (Exception e) {
+ assertEquals("Illegal character in Base64 encoded data.", e.getMessage());
+ }
+ }
+
+ private void check(String text, String encoded) throws UnsupportedEncodingException {
+ char[] s1 = Base64Coder.encode(text.getBytes("UTF-8"));
+ String t1 = new String(s1);
+ assertEquals(encoded, t1);
+ byte[] s2 = Base64Coder.decode(encoded.toCharArray());
+ String t2 = new String(s2, "UTF-8");
+ assertEquals(text, t2);
+ }
+}
diff --git a/src/test/java/examples/AnyObjectExampleTest.java b/src/test/java/examples/AnyObjectExampleTest.java
new file mode 100644
index 0000000..10ca00c
--- /dev/null
+++ b/src/test/java/examples/AnyObjectExampleTest.java
@@ -0,0 +1,59 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package examples;
+
+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() {
+ String doc = Util.getLocalResource("examples/any-object-example.yaml");
+ Yaml yaml = new Yaml();
+ Map<String, Object> object = (Map<String, Object>) yaml.load(doc);
+ 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 0000000..795f9d3
--- /dev/null
+++ b/src/test/java/examples/CollectionStyleTest.java
@@ -0,0 +1,37 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+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";
+ assertEquals("a: 1\nb: {c: 3, d: 4}\n", yaml.dump(yaml.load(document)));
+ }
+
+ public void testNestedStyle2() {
+ DumperOptions options = new DumperOptions();
+ options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
+ Yaml yaml = new Yaml(options);
+ String document = " a: 1\n b:\n c: 3\n d: 4\n";
+ assertEquals("a: 1\nb:\n c: 3\n d: 4\n", yaml.dump(yaml.load(document)));
+ }
+}
diff --git a/src/test/java/examples/CustomBeanResolverTest.java b/src/test/java/examples/CustomBeanResolverTest.java
new file mode 100644
index 0000000..ce59ab4
--- /dev/null
+++ b/src/test/java/examples/CustomBeanResolverTest.java
@@ -0,0 +1,83 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package examples;
+
+import java.math.BigDecimal;
+import java.util.regex.Pattern;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.NodeId;
+import org.yaml.snakeyaml.nodes.ScalarNode;
+
+/**
+ * http://code.google.com/p/snakeyaml/issues/detail?id=75
+ */
+public class CustomBeanResolverTest extends TestCase {
+ private final Pattern CUSTOM_PATTERN = Pattern.compile("\\d+%");
+
+ public void testOnlyBigDecimal() {
+ Yaml yaml = new Yaml(new BigBeanConstructor());
+ Foo foo = (Foo) yaml.load("bar: 50\nbaz: 35%\nbas: 1250");
+ assertEquals(50.0, foo.bar);
+ assertEquals("0.35", foo.baz.toString());
+ assertEquals("1250", foo.bas);
+ }
+
+ public void testPrimitive() {
+ Yaml yaml = new Yaml(new BigBeanConstructor());
+ Foo foo = (Foo) yaml.load("bar: 50%\nbaz: 35%\nbas: 1250%\nbaw: 35");
+ assertEquals(0.5, foo.bar);
+ assertEquals("0.35", foo.baz.toString());
+ assertEquals("1250%", foo.bas);
+ assertEquals("35", foo.baw.toString());
+ }
+
+ class BigBeanConstructor extends Constructor {
+ public BigBeanConstructor() {
+ super(Foo.class);
+ yamlClassConstructors.put(NodeId.scalar, new ConstructBig());
+ }
+
+ private class ConstructBig extends ConstructScalar {
+ public Object construct(Node node) {
+ if (node.getType().equals(BigDecimal.class)) {
+ String val = (String) constructScalar((ScalarNode) node);
+ if (CUSTOM_PATTERN.matcher(val).matches()) {
+ return new BigDecimal(val.substring(0, val.length() - 1))
+ .divide(new BigDecimal(100));
+ }
+ } else if (node.getType().isAssignableFrom(double.class)) {
+ String val = (String) constructScalar((ScalarNode) node);
+ if (CUSTOM_PATTERN.matcher(val).matches()) {
+ return new Double(val.substring(0, val.length() - 1)) / 100;
+ }
+ }
+ return super.construct(node);
+ }
+ }
+ }
+
+ public static class Foo {
+ public double bar = 0;
+ public BigDecimal baz;
+ public BigDecimal baw;
+ public String bas;
+ }
+}
diff --git a/src/test/java/examples/CustomConstructor.java b/src/test/java/examples/CustomConstructor.java
new file mode 100644
index 0000000..1d61a0a
--- /dev/null
+++ b/src/test/java/examples/CustomConstructor.java
@@ -0,0 +1,34 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package examples;
+
+import java.util.LinkedList;
+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 LinkedList<Object>();
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/examples/CustomImplicitResolverTest.java b/src/test/java/examples/CustomImplicitResolverTest.java
new file mode 100644
index 0000000..c5c0315
--- /dev/null
+++ b/src/test/java/examples/CustomImplicitResolverTest.java
@@ -0,0 +1,72 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package examples;
+
+import java.math.BigDecimal;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.AbstractConstruct;
+import org.yaml.snakeyaml.constructor.SafeConstructor;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.ScalarNode;
+import org.yaml.snakeyaml.nodes.Tag;
+
+/**
+ * Use custom implicit resolver when the runtime class is not defined.
+ * http://code.google.com/p/snakeyaml/issues/detail?id=75
+ */
+public class CustomImplicitResolverTest extends TestCase {
+ private final Tag CUSTOM_TAG = new Tag("!BigDecimalDividedBy100");
+ private final Pattern CUSTOM_PATTERN = Pattern.compile("\\d+%");
+
+ @SuppressWarnings("unchecked")
+ public void testImplicit() {
+ Yaml yaml = new Yaml(new BigConstructor());
+ yaml.addImplicitResolver(CUSTOM_TAG, CUSTOM_PATTERN, "-0123456789");
+ Map<String, Object> obj = (Map<String, Object>) yaml.load("bar: 50%");
+ assertEquals("0.5", obj.get("bar").toString());
+ assertEquals(BigDecimal.class, obj.get("bar").getClass());
+ }
+
+ public void testImplicitFailure() {
+ Yaml yaml = new Yaml(new BigConstructor());
+ yaml.addImplicitResolver(CUSTOM_TAG, Pattern.compile("\\d+%"), "-0123456789");
+ try {
+ yaml.load("bar: !!float 50%");
+ fail("Both implicit and explicit are present.");
+ } catch (NumberFormatException e) {
+ assertEquals("For input string: \"50%\"", e.getMessage());
+ }
+ }
+
+ class BigConstructor extends SafeConstructor {
+ public BigConstructor() {
+ this.yamlConstructors.put(CUSTOM_TAG, new ConstructBig());
+ }
+
+ private class ConstructBig extends AbstractConstruct {
+ public Object construct(Node node) {
+ String val = (String) constructScalar((ScalarNode) node);
+ return new BigDecimal(val.substring(0, val.length() - 1))
+ .divide(new BigDecimal(100));
+ }
+ }
+ }
+}
diff --git a/src/test/java/examples/CustomJavaObjectWithBinaryStringTest.java b/src/test/java/examples/CustomJavaObjectWithBinaryStringTest.java
new file mode 100644
index 0000000..755be99
--- /dev/null
+++ b/src/test/java/examples/CustomJavaObjectWithBinaryStringTest.java
@@ -0,0 +1,80 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package examples;
+
+import java.io.StringReader;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+
+public class CustomJavaObjectWithBinaryStringTest extends TestCase {
+ public static class Pojo {
+ private String data;
+
+ public Pojo() {
+ }
+
+ public Pojo(String data) {
+ this.data = data;
+ }
+
+ public String getData() {
+ return data;
+ }
+
+ public void setData(String data) {
+ this.data = data;
+ }
+
+ @Override public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((data == null) ? 0 : data.hashCode());
+ return result;
+ }
+
+ @Override public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ Pojo other = (Pojo) obj;
+ if (data == null) {
+ if (other.data != null)
+ return false;
+ } else if (!data.equals(other.data))
+ return false;
+ return true;
+ }
+
+ }
+
+ public void testDump() {
+ Yaml yaml = new Yaml();
+ Pojo expected = new Pojo(new String(new byte[] { 13, 14, 15, 16 }));
+ String output = yaml.dump(expected);
+
+ assertTrue(output.contains("data: !!binary |-"));
+ assertTrue(output.contains("DQ4PEA=="));
+
+ Pojo actual = (Pojo) yaml.load(new StringReader(output));
+ assertEquals(expected, actual);
+ }
+
+}
diff --git a/src/test/java/examples/CustomListExampleTest.java b/src/test/java/examples/CustomListExampleTest.java
new file mode 100644
index 0000000..11c98ca
--- /dev/null
+++ b/src/test/java/examples/CustomListExampleTest.java
@@ -0,0 +1,40 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package examples;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.Constructor;
+
+public class CustomListExampleTest extends TestCase {
+ @SuppressWarnings("unchecked")
+ public void testList() {
+ Yaml yaml = new Yaml(new CustomConstructor());
+ List<Integer> data = (List<Integer>) yaml.load("[1, 2, 3]");
+ assertTrue(data instanceof LinkedList);
+ }
+
+ class CustomConstructor extends Constructor {
+ @Override
+ protected List<Object> createDefaultList(int initSize) {
+ return new LinkedList<Object>();
+ }
+ }
+}
diff --git a/src/test/java/examples/CustomMapExampleTest.java b/src/test/java/examples/CustomMapExampleTest.java
new file mode 100644
index 0000000..95fe7fc
--- /dev/null
+++ b/src/test/java/examples/CustomMapExampleTest.java
@@ -0,0 +1,46 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package examples;
+
+import java.util.Map;
+import java.util.TreeMap;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.Constructor;
+
+public class CustomMapExampleTest extends TestCase {
+ public void testMap() {
+ Yaml yaml = new Yaml(new CustomConstructor());
+ @SuppressWarnings("unchecked")
+ Map<Integer, String> data = (Map<Integer, String>) 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 0000000..62e9262
--- /dev/null
+++ b/src/test/java/examples/Dice.java
@@ -0,0 +1,53 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+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 0000000..c0d0b63
--- /dev/null
+++ b/src/test/java/examples/DiceExampleTest.java
@@ -0,0 +1,161 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package examples;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.AbstractConstruct;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.constructor.SafeConstructor;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.ScalarNode;
+import org.yaml.snakeyaml.nodes.Tag;
+import org.yaml.snakeyaml.representer.Represent;
+import org.yaml.snakeyaml.representer.Representer;
+
+public class DiceExampleTest extends TestCase {
+ public void testRepresenter() {
+ Dice dice = new Dice(3, 6);
+ DumperOptions options = new DumperOptions();
+ options.setAllowReadOnlyProperties(true);
+ Yaml yaml = new Yaml(options);
+ String output = yaml.dump(dice);
+ assertEquals("!!examples.Dice {a: 3, b: 6}\n", output);
+ }
+
+ public void testDiceRepresenter() {
+ Dice dice = new Dice(3, 6);
+ Map<String, Dice> data = new HashMap<String, Dice>();
+ data.put("gold", dice);
+ Yaml yaml = new Yaml(new DiceRepresenter(), new DumperOptions());
+ String output = yaml.dump(data);
+ 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(new Tag("!dice"), value);
+ }
+ }
+ }
+
+ class DiceConstructor extends Constructor {
+ public DiceConstructor() {
+ this.yamlConstructors.put(new Tag("!dice"), new ConstructDice());
+ }
+
+ private class ConstructDice extends AbstractConstruct {
+ public Object construct(Node node) {
+ String val = (String) constructScalar((ScalarNode) node);
+ int position = val.indexOf('d');
+ Integer a = new Integer(val.substring(0, position));
+ Integer b = new Integer(val.substring(position + 1));
+ return new Dice(a, b);
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testConstructor() {
+ Yaml yaml = new Yaml(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"));
+ }
+
+ // the tag must start with a digit
+ @SuppressWarnings("unchecked")
+ public void testImplicitResolver() {
+ Yaml yaml = new Yaml(new DiceConstructor(), new DiceRepresenter());
+ // the tag must start with a digit
+ yaml.addImplicitResolver(new Tag("!dice"), Pattern.compile("\\d+d\\d+"), "123456789");
+ // dump
+ Map<String, Dice> treasure = new HashMap<String, Dice>();
+ treasure.put("treasure", new Dice(10, 20));
+ String output = yaml.dump(treasure);
+ 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"));
+ }
+
+ // the tag may start with anything
+ @SuppressWarnings("unchecked")
+ public void testImplicitResolverWithNull() {
+ Yaml yaml = new Yaml(new DiceConstructor(), new DiceRepresenter());
+ // the tag may start with anything
+ yaml.addImplicitResolver(new Tag("!dice"), Pattern.compile("\\d+d\\d+"), null);
+ // dump
+ Map<String, Dice> treasure = new HashMap<String, Dice>();
+ treasure.put("treasure", new Dice(10, 20));
+ String output = yaml.dump(treasure);
+ 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"));
+ }
+
+ static class DiceBean {
+ public Dice treasure;
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o)
+ return true;
+ if (!(o instanceof DiceBean))
+ return false;
+
+ DiceBean diceBean = (DiceBean) o;
+ if (treasure != null ? !treasure.equals(diceBean.treasure) : diceBean.treasure != null)
+ return false;
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return treasure != null ? treasure.hashCode() : 0;
+ }
+ }
+
+ public void testImplicitResolverJavaBean() {
+ Yaml yaml = new Yaml(new DiceConstructor(), new DiceRepresenter());
+ // the tag must start with a digit
+ yaml.addImplicitResolver(new Tag("!dice"), Pattern.compile("\\d+d\\d+"), "123456789");
+ // dump
+ DiceBean bean = new DiceBean();
+ bean.treasure = new Dice(10, 20);
+ String output = yaml.dump(bean);
+ assertEquals("!!examples.DiceExampleTest$DiceBean {treasure: 10d20}\n", output);
+ // load
+ Object loaded = yaml.load(output);
+ assertEquals(loaded, bean);
+ }
+}
diff --git a/src/test/java/examples/DumpExampleTest.java b/src/test/java/examples/DumpExampleTest.java
new file mode 100644
index 0000000..358c55c
--- /dev/null
+++ b/src/test/java/examples/DumpExampleTest.java
@@ -0,0 +1,135 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package examples;
+
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+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);
+ 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);
+ 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 ArrayList<Integer>();
+ for (int i = 1; i < 4; i++) {
+ docs.add(i);
+ }
+ DumperOptions options = new DumperOptions();
+ options.setExplicitStart(true);
+ Yaml yaml = new Yaml(options);
+ String result = yaml.dumpAll(docs.iterator());
+ assertNotNull(result);
+ assertTrue(result.contains("--- 2"));
+ }
+
+ public void testDumpCustomJavaClass() {
+ Hero hero = new Hero("Galain Ysseleg", -3, 2);
+ DumperOptions options = new DumperOptions();
+ options.setAllowReadOnlyProperties(true);
+ Yaml yaml = new Yaml(options);
+ String output = yaml.dump(hero);
+ assertEquals("!!examples.Hero {hp: -3, name: Galain Ysseleg, sp: 2}\n", output);
+ }
+
+ public void testDumperOptions() {
+ List<Integer> data = new ArrayList<Integer>();
+ for (int i = 0; i < 50; i++) {
+ data.add(i);
+ }
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(data);
+ 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);
+ assertTrue(output.contains("1, 2"));
+ }
+
+ public void testDumperOptionsCanonical() {
+ List<Integer> data = new ArrayList<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);
+ assertTrue(output.contains("---"));
+ assertTrue(output.contains("!!seq ["));
+ assertTrue(output.contains("!!int \"3\","));
+ }
+
+ public void testDumperOptionsFlowStyle() {
+ List<Integer> data = new ArrayList<Integer>();
+ for (int i = 0; i < 5; i++) {
+ data.add(i);
+ }
+ DumperOptions options = new DumperOptions();
+ options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
+ Yaml yaml = new Yaml(options);
+ String output = yaml.dump(data);
+ assertTrue(output.contains("- 0\n"));
+ assertTrue(output.contains("- 1\n"));
+ assertTrue(output.contains("- 4\n"));
+ }
+
+ public void testDumperOptionsStyle() {
+ List<Integer> data = new ArrayList<Integer>();
+ for (int i = 0; i < 5; i++) {
+ data.add(i);
+ }
+ DumperOptions options = new DumperOptions();
+ options.setDefaultScalarStyle(DumperOptions.ScalarStyle.DOUBLE_QUOTED);
+ Yaml yaml = new Yaml(options);
+ String output = yaml.dump(data);
+ 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 0000000..e309ed3
--- /dev/null
+++ b/src/test/java/examples/Hero.java
@@ -0,0 +1,42 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+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/IgnoreTagsExampleTest.java b/src/test/java/examples/IgnoreTagsExampleTest.java
new file mode 100644
index 0000000..eb175eb
--- /dev/null
+++ b/src/test/java/examples/IgnoreTagsExampleTest.java
@@ -0,0 +1,82 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package examples;
+
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.AbstractConstruct;
+import org.yaml.snakeyaml.constructor.Construct;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.error.YAMLException;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.Tag;
+
+public class IgnoreTagsExampleTest extends TestCase {
+ @SuppressWarnings("unchecked")
+ public void testLoad() {
+ String input = Util.getLocalResource("examples/unknown-tags-example.yaml");
+ // System.out.println(input);
+ Yaml yaml = new Yaml(new MyConstructor());
+ Map<String, Object> result = (Map<String, Object>) yaml.load(input);
+ // Check the result
+ assertNotNull(result);
+ assertEquals(3, result.size());
+ assertEquals("123", result.get("aaa"));
+ //
+ List<Object> bbb = (List<Object>) result.get("bbb");
+ assertEquals(2, bbb.size());
+ assertEquals(new Integer(111), bbb.get(0));
+ assertEquals("ddd", bbb.get(1));
+ //
+ Map<String, Object> ccc = (Map<String, Object>) result.get("ccc");
+ assertEquals(2, ccc.size());
+ assertEquals(1.0, ccc.get("x"));
+ assertEquals(3.1416, ccc.get("y"));
+ }
+
+ private class MyConstructor extends Constructor {
+ private Construct original;
+
+ public MyConstructor() {
+ original = this.yamlConstructors.get(null);
+ this.yamlConstructors.put(null, new IgnoringConstruct());
+ }
+
+ private class IgnoringConstruct extends AbstractConstruct {
+ public Object construct(Node node) {
+ if (node.getTag().startsWith("!KnownTag")) {
+ return original.construct(node);
+ } else {
+ switch (node.getNodeId()) {
+ case scalar:
+ return yamlConstructors.get(Tag.STR).construct(node);
+ case sequence:
+ return yamlConstructors.get(Tag.SEQ).construct(node);
+ case mapping:
+ return yamlConstructors.get(Tag.MAP).construct(node);
+ default:
+ throw new YAMLException("Unexpected node");
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/test/java/examples/LoadExampleTest.java b/src/test/java/examples/LoadExampleTest.java
new file mode 100644
index 0000000..e66ee1a
--- /dev/null
+++ b/src/test/java/examples/LoadExampleTest.java
@@ -0,0 +1,72 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package examples;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+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";
+ List<String> list = (List<String>) yaml.load(document);
+ assertEquals("[Hesperiidae, Papilionidae, Apatelodidae, Epiplemidae]", list.toString());
+ }
+
+ public void testLoadFromString() {
+ Yaml yaml = new Yaml();
+ String document = "hello: 25";
+ @SuppressWarnings("unchecked")
+ Map<String, Integer> map = (Map<String, Integer>) yaml.load(document);
+ assertEquals("{hello=25}", map.toString());
+ assertEquals(new Integer(25), map.get("hello"));
+ }
+
+ public void testLoadFromStream() throws IOException {
+ 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("UTF-8")));
+ assertEquals("test2", data);
+ input.close();
+ }
+
+ public void testLoadManyDocuments() throws IOException {
+ 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)) {
+ assertNotNull(data);
+ assertTrue(data.toString().length() > 1);
+ counter++;
+ }
+ assertEquals(3, counter);
+ input.close();
+ }
+}
diff --git a/src/test/java/examples/SafeConstructorExampleTest.java b/src/test/java/examples/SafeConstructorExampleTest.java
new file mode 100644
index 0000000..80af417
--- /dev/null
+++ b/src/test/java/examples/SafeConstructorExampleTest.java
@@ -0,0 +1,51 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package examples;
+
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.SafeConstructor;
+
+public class SafeConstructorExampleTest extends TestCase {
+ @SuppressWarnings("unchecked")
+ public void testConstruct() {
+ String doc = "- 5\n- Person\n- true";
+ Yaml yaml = new Yaml(new SafeConstructor());
+ List<Object> list = (List<Object>) yaml.load(doc);
+ 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() {
+ String doc = "- 5\n- !org.yaml.snakeyaml.constructor.Person\n firstName: Andrey\n age: 99\n- true";
+ Yaml yaml = new Yaml(new SafeConstructor());
+ try {
+ yaml.load(doc);
+ fail("Custom Java classes should not be created.");
+ } catch (Exception e) {
+ assertEquals(
+ "could not determine a constructor for the tag !org.yaml.snakeyaml.constructor.Person\n"
+ + " in 'string', line 2, column 3:\n"
+ + " - !org.yaml.snakeyaml.constructor. ... \n" + " ^\n",
+ e.getMessage());
+ }
+ }
+}
diff --git a/src/test/java/examples/SelectiveConstructorTest.java b/src/test/java/examples/SelectiveConstructorTest.java
new file mode 100644
index 0000000..1117d46
--- /dev/null
+++ b/src/test/java/examples/SelectiveConstructorTest.java
@@ -0,0 +1,101 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package examples;
+
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.nodes.MappingNode;
+import org.yaml.snakeyaml.nodes.NodeId;
+
+/**
+ * Example for http://code.google.com/p/snakeyaml/wiki/howto
+ */
+public class SelectiveConstructorTest extends TestCase {
+ class SelectiveConstructor extends Constructor {
+ public SelectiveConstructor() {
+ // define a custom way to create a mapping node
+ yamlClassConstructors.put(NodeId.mapping, new MyPersistentObjectConstruct());
+ }
+
+ class MyPersistentObjectConstruct extends Constructor.ConstructMapping {
+ @Override
+ protected Object constructJavaBean2ndStep(MappingNode node, Object object) {
+ Class<?> type = node.getType();
+ if (type.equals(MyPersistentObject.class)) {
+ // create a map
+ Map<Object, Object> map = constructMapping(node);
+ String id = (String) map.get("id");
+ return new MyPersistentObject(id, 17);
+ } else {
+ // create JavaBean
+ return super.constructJavaBean2ndStep(node, object);
+ }
+ }
+ }
+ }
+
+ public void testConstructor() {
+ Yaml yaml = new Yaml(new SelectiveConstructor());
+ List<?> data = (List<?>) yaml
+ .load("- 1\n- 2\n- !!examples.MyPersistentObject {amount: 222, id: persistent}");
+ // System.out.println(data);
+ assertEquals(3, data.size());
+ MyPersistentObject myObject = (MyPersistentObject) data.get(2);
+ assertEquals(17, myObject.getAmount());
+ assertEquals("persistent", myObject.getId());
+ }
+}
+
+class MyPersistentObject {
+ private String id;
+ private int amount;
+
+ public MyPersistentObject() {
+ this.id = "noid";
+ this.amount = 222;
+ }
+
+ public MyPersistentObject(String id, int amount) {
+ this.id = id;
+ this.amount = amount;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public int getAmount() {
+ return amount;
+ }
+
+ public void setAmount(int amount) {
+ this.amount = amount;
+ }
+
+ @Override
+ public String toString() {
+ return "MyPersistentObject [id=" + id + ", amount=" + amount + "]";
+ }
+}
diff --git a/src/test/java/examples/SpringTest.java b/src/test/java/examples/SpringTest.java
new file mode 100644
index 0000000..5a79a60
--- /dev/null
+++ b/src/test/java/examples/SpringTest.java
@@ -0,0 +1,36 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+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/examples/collections/ListFileldBeanTest.java b/src/test/java/examples/collections/ListFileldBeanTest.java
new file mode 100644
index 0000000..0bea870
--- /dev/null
+++ b/src/test/java/examples/collections/ListFileldBeanTest.java
@@ -0,0 +1,121 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package examples.collections;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+
+/**
+ * Test public field ListBean->List<Developer> developers <br/>
+ * Developer class must be properly recognised
+ */
+public class ListFileldBeanTest extends TestCase {
+ public void testDumpList() {
+ ListFieldBean bean = new ListFieldBean();
+ List<String> list = new ArrayList<String>();
+ list.add("aaa");
+ list.add("bbb");
+ bean.setChildren(list);
+ List<Developer> developers = new ArrayList<Developer>();
+ developers.add(new Developer("Fred", "creator"));
+ developers.add(new Developer("John", "committer"));
+ bean.developers = developers;
+ bean.setName("Bean123");
+ Yaml yaml = new Yaml();
+ String output = yaml.dumpAsMap(bean);
+ // System.out.println(output);
+ String etalon = Util.getLocalResource("examples/list-bean-1.yaml");
+ assertEquals(etalon, output);
+ }
+
+ public void testLoadList() {
+ String output = Util.getLocalResource("examples/list-bean-1.yaml");
+ // System.out.println(output);
+ Yaml beanLoader = new Yaml();
+ ListFieldBean parsed = beanLoader.loadAs(output, ListFieldBean.class);
+ assertNotNull(parsed);
+ List<String> list2 = parsed.getChildren();
+ assertEquals(2, list2.size());
+ assertEquals("aaa", list2.get(0));
+ assertEquals("bbb", list2.get(1));
+ List<Developer> developers = parsed.developers;
+ assertEquals(2, developers.size());
+ assertEquals("Developer must be recognised.", Developer.class, developers.get(0).getClass());
+ Developer fred = developers.get(0);
+ assertEquals("Fred", fred.getName());
+ assertEquals("creator", fred.getRole());
+ }
+
+ public static class ListFieldBean {
+ private List<String> children;
+ private String name;
+ public List<Developer> developers;
+
+ public ListFieldBean() {
+ name = "Bean456";
+ }
+
+ public List<String> getChildren() {
+ return children;
+ }
+
+ public void setChildren(List<String> children) {
+ this.children = children;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+ }
+
+ public static class Developer {
+ private String name;
+ private String role;
+
+ public Developer() {
+ }
+
+ public Developer(String name, String role) {
+ this.name = name;
+ this.role = role;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getRole() {
+ return role;
+ }
+
+ public void setRole(String role) {
+ this.role = role;
+ }
+ }
+}
diff --git a/src/test/java/examples/collections/TypeSafeListNoGerericsTest.java b/src/test/java/examples/collections/TypeSafeListNoGerericsTest.java
new file mode 100644
index 0000000..63c38cd
--- /dev/null
+++ b/src/test/java/examples/collections/TypeSafeListNoGerericsTest.java
@@ -0,0 +1,130 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package examples.collections;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+
+/**
+ * Test ListBean->List developers <br/>
+ * Developer class cannot be properly recognised
+ */
+public class TypeSafeListNoGerericsTest extends TestCase {
+ public void testDumpList() {
+ ListBean bean = new ListBean();
+ List<String> list = new ArrayList<String>();
+ list.add("aaa");
+ list.add("bbb");
+ bean.setChildren(list);
+ List<Developer> developers = new ArrayList<Developer>();
+ developers.add(new Developer("Fred", "creator"));
+ developers.add(new Developer("John", "committer"));
+ bean.setDevelopers(developers);
+ Yaml yaml = new Yaml();
+ String output = yaml.dumpAsMap(bean);
+ // System.out.println(output);
+ String etalon = Util.getLocalResource("examples/list-bean-4.yaml");
+ assertEquals(etalon, output);
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testLoadList() {
+ String output = Util.getLocalResource("examples/list-bean-1.yaml");
+ // System.out.println(output);
+ Yaml beanLoader = new Yaml();
+ ListBean parsed = beanLoader.loadAs(output, ListBean.class);
+ assertNotNull(parsed);
+ List<String> list2 = parsed.getChildren();
+ assertEquals(2, list2.size());
+ assertEquals("aaa", list2.get(0));
+ assertEquals("bbb", list2.get(1));
+ List<Map<String, String>> developers = parsed.getDevelopers();
+ assertEquals(2, developers.size());
+ Map<String, String> fred = developers.get(0);
+ assertEquals("Fred", fred.get("name"));
+ assertEquals("creator", fred.get("role"));
+ }
+
+ @SuppressWarnings("rawtypes")
+ public static class ListBean {
+ private List<String> children;
+ private String name;
+ private List developers;
+
+ public ListBean() {
+ name = "Bean123";
+ }
+
+ public List<String> getChildren() {
+ return children;
+ }
+
+ public void setChildren(List<String> children) {
+ this.children = children;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public List getDevelopers() {
+ return developers;
+ }
+
+ public void setDevelopers(List developers) {
+ this.developers = developers;
+ }
+ }
+
+ public static class Developer {
+ private String name;
+ private String role;
+
+ public Developer() {
+ }
+
+ public Developer(String name, String role) {
+ this.name = name;
+ this.role = role;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getRole() {
+ return role;
+ }
+
+ public void setRole(String role) {
+ this.role = role;
+ }
+ }
+}
diff --git a/src/test/java/examples/collections/TypeSafeListTest.java b/src/test/java/examples/collections/TypeSafeListTest.java
new file mode 100644
index 0000000..f6c9c45
--- /dev/null
+++ b/src/test/java/examples/collections/TypeSafeListTest.java
@@ -0,0 +1,128 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package examples.collections;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+
+/**
+ * Test ListBean->List<Developer> developers <br/>
+ * Developer class must be properly recognised
+ */
+public class TypeSafeListTest extends TestCase {
+ public void testDumpList() {
+ ListBean1 bean = new ListBean1();
+ List<String> list = new ArrayList<String>();
+ list.add("aaa");
+ list.add("bbb");
+ bean.setChildren(list);
+ List<Developer> developers = new ArrayList<Developer>();
+ developers.add(new Developer("Fred", "creator"));
+ developers.add(new Developer("John", "committer"));
+ bean.setDevelopers(developers);
+ Yaml yaml = new Yaml();
+ String output = yaml.dumpAsMap(bean);
+ // System.out.println(output);
+ String etalon = Util.getLocalResource("examples/list-bean-1.yaml");
+ assertEquals(etalon, output);
+ }
+
+ public void testLoadList() {
+ String output = Util.getLocalResource("examples/list-bean-1.yaml");
+ // System.out.println(output);
+ Yaml beanLoader = new Yaml();
+ ListBean1 parsed = beanLoader.loadAs(output, ListBean1.class);
+ assertNotNull(parsed);
+ List<String> list2 = parsed.getChildren();
+ assertEquals(2, list2.size());
+ assertEquals("aaa", list2.get(0));
+ assertEquals("bbb", list2.get(1));
+ List<Developer> developers = parsed.getDevelopers();
+ assertEquals(2, developers.size());
+ assertEquals("Developer must be recognised.", Developer.class, developers.get(0).getClass());
+ Developer fred = developers.get(0);
+ assertEquals("Fred", fred.getName());
+ assertEquals("creator", fred.getRole());
+ }
+
+ public static class ListBean1 {
+ private List<String> children;
+ private String name;
+ private List<Developer> developers;
+
+ public ListBean1() {
+ name = "Bean123";
+ }
+
+ public List<String> getChildren() {
+ return children;
+ }
+
+ public void setChildren(List<String> children) {
+ this.children = children;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public List<Developer> getDevelopers() {
+ return developers;
+ }
+
+ public void setDevelopers(List<Developer> developers) {
+ this.developers = developers;
+ }
+ }
+
+ public static class Developer {
+ private String name;
+ private String role;
+
+ public Developer() {
+ }
+
+ public Developer(String name, String role) {
+ this.name = name;
+ this.role = role;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getRole() {
+ return role;
+ }
+
+ public void setRole(String role) {
+ this.role = role;
+ }
+ }
+}
diff --git a/src/test/java/examples/collections/TypeSafeListWithInterfaceTest.java b/src/test/java/examples/collections/TypeSafeListWithInterfaceTest.java
new file mode 100644
index 0000000..4f6c08c
--- /dev/null
+++ b/src/test/java/examples/collections/TypeSafeListWithInterfaceTest.java
@@ -0,0 +1,172 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package examples.collections;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+
+/**
+ * Test ListBean->List<Human> developers <br/>
+ * Human is an interface and the global tags are required
+ */
+public class TypeSafeListWithInterfaceTest extends TestCase {
+ public void testDumpList() {
+ ListBean bean = new ListBean();
+ List<String> list = new ArrayList<String>();
+ list.add("aaa");
+ list.add("bbb");
+ bean.setChildren(list);
+ List<Human> developers = new ArrayList<Human>();
+ developers.add(new Developer("Fred", "creator"));
+ developers.add(new Committer("John", "committer", 34));
+ bean.setDevelopers(developers);
+ Yaml yaml = new Yaml();
+ String output = yaml.dumpAsMap(bean);
+ // System.out.println(output);
+ String etalon = Util.getLocalResource("examples/list-bean-2.yaml");
+ assertEquals(etalon, output);
+ }
+
+ public void testLoadWrongList() {
+ String output = Util.getLocalResource("examples/list-bean-1.yaml");
+ // System.out.println(output);
+ Yaml beanLoader = new Yaml();
+ try {
+ beanLoader.loadAs(output, ListBean.class);
+ fail("Global tags are required since Human is an interface.");
+ } catch (Exception e) {
+ assertTrue(e.getMessage(), e.getMessage().contains("Cannot create property=developers"));
+ }
+ }
+
+ public void testLoadList() {
+ String output = Util.getLocalResource("examples/list-bean-2.yaml");
+ // System.out.println(output);
+ Yaml beanLoader = new Yaml();
+ ListBean parsed = beanLoader.loadAs(output, ListBean.class);
+ assertNotNull(parsed);
+ List<String> list2 = parsed.getChildren();
+ assertEquals(2, list2.size());
+ assertEquals("aaa", list2.get(0));
+ assertEquals("bbb", list2.get(1));
+ List<Human> developers = parsed.getDevelopers();
+ assertEquals(2, developers.size());
+ assertEquals("Developer must be recognised.", Developer.class, developers.get(0).getClass());
+ Developer fred = (Developer) developers.get(0);
+ assertEquals("Fred", fred.getName());
+ assertEquals("creator", fred.getRole());
+ Committer john = (Committer) developers.get(1);
+ assertEquals("John", john.getName());
+ assertEquals("committer", john.getRole());
+ assertEquals(34, john.getKey());
+ }
+
+ public static class ListBean {
+ private List<String> children;
+ private String name;
+ private List<Human> developers;
+
+ public ListBean() {
+ name = "Bean123";
+ }
+
+ public List<String> getChildren() {
+ return children;
+ }
+
+ public void setChildren(List<String> children) {
+ this.children = children;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public List<Human> getDevelopers() {
+ return developers;
+ }
+
+ public void setDevelopers(List<Human> developers) {
+ this.developers = developers;
+ }
+ }
+
+ public static interface Human {
+
+ public String getName();
+
+ public void setName(String name);
+
+ }
+
+ public static class Developer implements Human {
+ private String name;
+ private String role;
+
+ public Developer() {
+ }
+
+ public Developer(String name, String role) {
+ this.name = name;
+ this.role = role;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getRole() {
+ return role;
+ }
+
+ public void setRole(String role) {
+ this.role = role;
+ }
+ }
+
+ public static class Committer extends Developer {
+ private int key;
+
+ public Committer() {
+ }
+
+ public Committer(String string, String string2, int i) {
+ super(string, string2);
+ this.key = i;
+ }
+
+ public int getKey() {
+ return key;
+ }
+
+ public void setKey(int key) {
+ this.key = key;
+ }
+ }
+}
diff --git a/src/test/java/examples/collections/TypeSafeMap2Test.java b/src/test/java/examples/collections/TypeSafeMap2Test.java
new file mode 100644
index 0000000..74673b3
--- /dev/null
+++ b/src/test/java/examples/collections/TypeSafeMap2Test.java
@@ -0,0 +1,230 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package examples.collections;
+
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+
+/**
+ * Test MapBean->Map<Enum, Developer> developers <br/>
+ * Developer class must be properly recognised
+ */
+public class TypeSafeMap2Test extends TestCase {
+ public void testDumpMap() {
+ MapBean2 bean = new MapBean2();
+ Map<Developer2, Color> data = new LinkedHashMap<Developer2, Color>();
+ data.put(new Developer2("Andy", "tester"), Color.BLACK);
+ data.put(new Developer2("Lisa", "owner"), Color.RED);
+ bean.setData(data);
+ Map<Color, Developer2> developers = new LinkedHashMap<Color, Developer2>();
+ developers.put(Color.WHITE, new Developer2("Fred", "creator"));
+ developers.put(Color.BLACK, new Developer2("John", "committer"));
+ bean.setDevelopers(developers);
+ Yaml yaml = new Yaml();
+ String output = yaml.dumpAsMap(bean);
+ // System.out.println(output);
+ String etalon = Util.getLocalResource("examples/map-bean-12.yaml");
+ assertEquals(etalon, output);
+ }
+
+ public void testMap2() {
+ MapBean2 bean = new MapBean2();
+ Map<Developer2, Color> data = new LinkedHashMap<Developer2, Color>();
+ data.put(new Developer2("Andy", "tester"), Color.BLACK);
+ data.put(new SuperMan("Bill", "cleaner", false), Color.BLACK);
+ data.put(new Developer2("Lisa", "owner"), Color.RED);
+ bean.setData(data);
+ Map<Color, Developer2> developers = new LinkedHashMap<Color, Developer2>();
+ developers.put(Color.WHITE, new Developer2("Fred", "creator"));
+ developers.put(Color.RED, new SuperMan("Jason", "contributor", true));
+ developers.put(Color.BLACK, new Developer2("John", "committer"));
+ bean.setDevelopers(developers);
+ Yaml yaml = new Yaml();
+ String output = yaml.dumpAsMap(bean);
+ // System.out.println(output);
+ String etalon = Util.getLocalResource("examples/map-bean-13.yaml");
+ assertEquals(etalon, output);
+ // load
+ Yaml beanLoader = new Yaml();
+ MapBean2 parsed = beanLoader.loadAs(etalon, MapBean2.class);
+ assertNotNull(parsed);
+ Map<Developer2, Color> parsedData = parsed.getData();
+ assertEquals(3, parsedData.size());
+ assertTrue(parsedData.containsKey(new SuperMan("Bill", "cleaner", false)));
+ assertEquals(Color.BLACK, parsedData.get(new SuperMan("Bill", "cleaner", false)));
+ //
+ Map<Color, Developer2> parsedDevelopers = parsed.getDevelopers();
+ assertEquals(3, parsedDevelopers.size());
+ assertEquals(new SuperMan("Jason", "contributor", true), parsedDevelopers.get(Color.RED));
+ }
+
+ public void testLoadMap() {
+ String output = Util.getLocalResource("examples/map-bean-12.yaml");
+ // System.out.println(output);
+ Yaml beanLoader = new Yaml();
+ MapBean2 parsed = beanLoader.loadAs(output, MapBean2.class);
+ assertNotNull(parsed);
+ Map<Developer2, Color> data = parsed.getData();
+ assertEquals(2, data.size());
+ Iterator<Developer2> iter = data.keySet().iterator();
+ Developer2 first = iter.next();
+ assertEquals("Andy", first.getName());
+ assertEquals("tester", first.getRole());
+ assertEquals(Color.BLACK, data.get(first));
+ Developer2 second = iter.next();
+ assertEquals("Lisa", second.getName());
+ assertEquals("owner", second.getRole());
+ assertEquals(Color.RED, data.get(second));
+ //
+ Map<Color, Developer2> developers = parsed.getDevelopers();
+ assertEquals(2, developers.size());
+ Iterator<Color> iter2 = developers.keySet().iterator();
+ Color firstColor = iter2.next();
+ assertEquals(Color.WHITE, firstColor);
+ Developer2 dev1 = developers.get(firstColor);
+ assertEquals("Fred", dev1.getName());
+ assertEquals("creator", dev1.getRole());
+ Color secondColor = iter2.next();
+ assertEquals(Color.BLACK, secondColor);
+ Developer2 dev2 = developers.get(secondColor);
+ assertEquals("John", dev2.getName());
+ assertEquals("committer", dev2.getRole());
+ }
+
+ public static enum Color {
+ WHITE, BLACK, RED;
+ }
+
+ public static class MapBean2 {
+ private Map<Developer2, Color> data;
+ private String name;
+ private Map<Color, Developer2> developers;
+
+ public MapBean2() {
+ name = "Bean123";
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Map<Color, Developer2> getDevelopers() {
+ return developers;
+ }
+
+ public void setDevelopers(Map<Color, Developer2> developers) {
+ this.developers = developers;
+ }
+
+ public Map<Developer2, Color> getData() {
+ return data;
+ }
+
+ public void setData(Map<Developer2, Color> data) {
+ this.data = data;
+ }
+
+ }
+
+ public static class Developer2 implements Comparable<Developer2> {
+ private String name;
+ private String role;
+
+ public Developer2() {
+ }
+
+ private Developer2(String name, String role) {
+ this.name = name;
+ this.role = role;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getRole() {
+ return role;
+ }
+
+ public void setRole(String role) {
+ this.role = role;
+ }
+
+ public int compareTo(Developer2 o) {
+ return name.compareTo(o.name);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof Developer2) {
+ return toString().equals(obj.toString());
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return toString().hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return "Developer " + name + " " + role;
+ }
+
+ }
+
+ public static class SuperMan extends Developer2 {
+ private boolean smart;
+
+ public SuperMan() {
+ super();
+ }
+
+ private SuperMan(String name, String role, boolean smart) {
+ super(name, role);
+ this.smart = smart;
+ }
+
+ public boolean isSmart() {
+ return smart;
+ }
+
+ public void setSmart(boolean smart) {
+ this.smart = smart;
+ }
+
+ @Override
+ public String toString() {
+ return "Super" + super.toString();
+ }
+ }
+}
diff --git a/src/test/java/examples/collections/TypeSafeMapImplementationsTest.java b/src/test/java/examples/collections/TypeSafeMapImplementationsTest.java
new file mode 100644
index 0000000..2eff986
--- /dev/null
+++ b/src/test/java/examples/collections/TypeSafeMapImplementationsTest.java
@@ -0,0 +1,203 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package examples.collections;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+
+/**
+ * Test different Map implementations as JavaBean properties
+ */
+public class TypeSafeMapImplementationsTest extends TestCase {
+ public void testDumpMap() {
+ MapBean bean = new MapBean();
+ SortedMap<String, String> sortedMap = new TreeMap<String, String>();
+ sortedMap.put("2", "two");
+ sortedMap.put("1", "one");
+ bean.setSorted(sortedMap);
+ Properties props = new Properties();
+ props.setProperty("key1", "value1");
+ props.setProperty("key2", "value2");
+ bean.setProperties(props);
+ Yaml yaml = new Yaml();
+ String output = yaml.dumpAsMap(bean);
+ // System.out.println(output);
+ String etalon = Util.getLocalResource("examples/map-bean-1.yaml");
+ assertEquals(etalon, output);
+ }
+
+ public void testLoadMap() {
+ String output = Util.getLocalResource("examples/map-bean-1.yaml");
+ // System.out.println(output);
+ Yaml beanLoader = new Yaml();
+ MapBean parsed = beanLoader.loadAs(output, MapBean.class);
+ assertNotNull(parsed);
+ SortedMap<String, String> sortedMap = parsed.getSorted();
+ assertEquals(2, sortedMap.size());
+ assertEquals("one", sortedMap.get("1"));
+ assertEquals("two", sortedMap.get("2"));
+ String first = sortedMap.keySet().iterator().next();
+ assertEquals("1", first);
+ //
+ Properties props = parsed.getProperties();
+ assertEquals(2, props.size());
+ assertEquals("value1", props.getProperty("key1"));
+ assertEquals("value2", props.getProperty("key2"));
+ }
+
+ public static class MapBean {
+ private SortedMap<String, String> sorted;
+ private Properties properties;
+ private String name;
+
+ public MapBean() {
+ name = "Bean123";
+ }
+
+ public SortedMap<String, String> getSorted() {
+ return sorted;
+ }
+
+ public void setSorted(SortedMap<String, String> sorted) {
+ this.sorted = sorted;
+ }
+
+ public Properties getProperties() {
+ return properties;
+ }
+
+ public void setProperties(Properties properties) {
+ this.properties = properties;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testNoJavaBeanMap() {
+ List<Object> list = new ArrayList<Object>(3);
+ SortedMap<String, String> sortedMap = new TreeMap<String, String>();
+ sortedMap.put("2", "two");
+ sortedMap.put("1", "one");
+ list.add(sortedMap);
+ Properties props = new Properties();
+ props.setProperty("key1", "value1");
+ props.setProperty("key2", "value2");
+ list.add(props);
+ list.add("aaa");
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(list);
+ // System.out.println(output);
+ String etalon = Util.getLocalResource("examples/map-bean-2.yaml");
+ assertEquals(etalon, output);
+ // load
+ List<Object> list2 = (List<Object>) yaml.load(output);
+ assertEquals(3, list2.size());
+ Map<Object, Object> map1 = (Map<Object, Object>) list.get(0);// it was
+ // SortedMap
+ assertEquals(2, map1.size());
+ assertEquals("one", map1.get("1"));
+ assertEquals("two", map1.get("2"));
+ Map<Object, Object> map2 = (Map<Object, Object>) list.get(1);// it was
+ // Properties
+ assertEquals(2, map2.size());
+ assertEquals("value1", map2.get("key1"));
+ assertEquals("value2", map2.get("key2"));
+ assertEquals("aaa", list.get(2));
+ }
+
+ public void testRecursiveNoJavaBeanMap1() {
+ SortedMap<String, Object> sortedMap = new TreeMap<String, Object>();
+ sortedMap.put("2", "two");
+ sortedMap.put("1", "one");
+ sortedMap.put("3", sortedMap);
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(sortedMap);
+ // System.out.println(output);
+ String etalon = Util.getLocalResource("examples/map-recursive-1.yaml");
+ assertEquals(etalon, output);
+ // load with different order
+ @SuppressWarnings("unchecked")
+ Map<Object, Object> map1 = (Map<Object, Object>) yaml.load(Util
+ .getLocalResource("examples/map-recursive-1_1.yaml"));
+ assertEquals(3, map1.size());
+ assertEquals("one", map1.get("1"));
+ assertEquals("two", map1.get("2"));
+ // test that the order is taken from YAML instead of sorting
+ String first = (String) map1.keySet().iterator().next();
+ assertEquals("2", first);
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testRecursiveNoJavaBeanProperties2() {
+ Properties props = new Properties();
+ props.setProperty("key1", "value1");
+ props.setProperty("key2", "value2");
+ Map<Object, Object> map = props;
+ map.put("key3", props);
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(props);
+ // System.out.println(output);
+ String etalon = Util.getLocalResource("examples/map-recursive-2.yaml");
+ assertEquals(etalon, output);
+ // load
+ Map<Object, Object> map2 = (Map<Object, Object>) yaml.load(output);
+ assertEquals(3, map2.size());
+ assertEquals("value1", map2.get("key1"));
+ assertEquals("value2", map2.get("key2"));
+ }
+
+ public void testRecursiveNoJavaBeanMap3() {
+ Yaml yaml = new Yaml();
+ String output = Util.getLocalResource("examples/map-recursive-3.yaml");
+ // System.out.println(output);
+ @SuppressWarnings("unchecked")
+ SortedMap<Object, Object> map1 = (SortedMap<Object, Object>) yaml.load(output);
+ assertEquals(3, map1.size());
+ assertEquals("one", map1.get("1"));
+ assertEquals("two", map1.get("2"));
+ // test that the order is NOT taken from YAML but sorted
+ String first = (String) map1.keySet().iterator().next();
+ assertEquals("1", first);
+ }
+
+ public void testRecursiveNoJavaBeanProperties4() {
+ Yaml yaml = new Yaml();
+ String output = Util.getLocalResource("examples/map-recursive-4.yaml");
+ // System.out.println(output);
+ try {
+ yaml.load(output);
+ fail("Recursive Properties are not supported.");
+ } catch (Exception e) {
+ assertTrue(e.getMessage(), e.getMessage().contains("Properties must not be recursive."));
+ }
+ }
+}
diff --git a/src/test/java/examples/collections/TypeSafeMapTest.java b/src/test/java/examples/collections/TypeSafeMapTest.java
new file mode 100644
index 0000000..d21b954
--- /dev/null
+++ b/src/test/java/examples/collections/TypeSafeMapTest.java
@@ -0,0 +1,219 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package examples.collections;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+
+/**
+ * Test MapBean->Map<String, Developer> developers <br/>
+ * Developer class must be properly recognised
+ */
+public class TypeSafeMapTest extends TestCase {
+ public void testDumpMap() {
+ MapBean bean = new MapBean();
+ Map<String, Integer> data = new LinkedHashMap<String, Integer>();
+ data.put("aaa", 1);
+ data.put("bbb", 2);
+ data.put("zzz", 3);
+ bean.setData(data);
+ Map<String, Developer2> developers = new LinkedHashMap<String, Developer2>();
+ developers.put("team1", new Developer2("Fred", "creator"));
+ developers.put("team2", new Developer2("John", "committer"));
+ bean.setDevelopers(developers);
+ Yaml yaml = new Yaml();
+ String output = yaml.dumpAsMap(bean);
+ // System.out.println(output);
+ String etalon = Util.getLocalResource("examples/map-bean-10.yaml");
+ assertEquals(etalon, output);
+ }
+
+ public void testDumpMap2() {
+ MapBean bean = new MapBean();
+ Map<String, Integer> data = new LinkedHashMap<String, Integer>();
+ data.put("aaa", 1);
+ data.put("bbb", 2);
+ bean.setData(data);
+ Map<String, Developer2> developers = new LinkedHashMap<String, Developer2>();
+ developers.put("team1", new Developer2("Fred", "creator"));
+ developers.put("team2", new Developer2("John", "committer"));
+ developers.put("team3", new Developer222("Bill", "head"));
+ bean.setDevelopers(developers);
+ Yaml yaml = new Yaml();
+ String output = yaml.dumpAsMap(bean);
+ // System.out.println(output);
+ String etalon = Util.getLocalResource("examples/map-bean-11.yaml");
+ assertEquals(etalon, output);
+ }
+
+ public void testLoadMap() {
+ String output = Util.getLocalResource("examples/map-bean-10.yaml");
+ // System.out.println(output);
+ Yaml beanLoader = new Yaml();
+ MapBean parsed = beanLoader.loadAs(output, MapBean.class);
+ assertNotNull(parsed);
+ Map<String, Integer> data = parsed.getData();
+ assertEquals(3, data.size());
+ assertEquals(new Integer(1), data.get("aaa"));
+ assertEquals(new Integer(2), data.get("bbb"));
+ assertEquals(new Integer(3), data.get("zzz"));
+ Map<String, Developer2> developers = parsed.getDevelopers();
+ assertEquals(2, developers.size());
+ assertEquals("Developer must be recognised.", Developer2.class, developers.get("team1")
+ .getClass());
+ Developer2 fred = developers.get("team1");
+ assertEquals("Fred", fred.getName());
+ assertEquals("creator", fred.getRole());
+ }
+
+ public static class MapBean {
+ private Map<String, Integer> data;
+ private String name;
+ private Map<String, Developer2> developers;
+
+ public MapBean() {
+ name = "Bean123";
+ }
+
+ public Map<String, Integer> getData() {
+ return data;
+ }
+
+ public void setData(Map<String, Integer> data) {
+ this.data = data;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Map<String, Developer2> getDevelopers() {
+ return developers;
+ }
+
+ public void setDevelopers(Map<String, Developer2> developers) {
+ this.developers = developers;
+ }
+ }
+
+ public static class Developer2 {
+ private String name;
+ private String role;
+
+ public Developer2() {
+ }
+
+ public Developer2(String name, String role) {
+ this.name = name;
+ this.role = role;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getRole() {
+ return role;
+ }
+
+ public void setRole(String role) {
+ this.role = role;
+ }
+ }
+
+ public static class Developer222 extends Developer2 {
+ public Developer222() {
+ super();
+ }
+
+ public Developer222(String name, String role) {
+ super(name, role);
+ }
+ }
+
+ /*
+ * No generic collection
+ */
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ public void testLoadMapWithObject() {
+ String output = Util.getLocalResource("examples/map-bean-10.yaml");
+ // System.out.println(output);
+ Yaml beanLoader = new Yaml();
+ MapBeanNoGenerics parsed = beanLoader.loadAs(output, MapBeanNoGenerics.class);
+ assertNotNull(parsed);
+ Map<String, Integer> data = parsed.getData();
+ assertEquals(3, data.size());
+ assertEquals(new Integer(1), data.get("aaa"));
+ assertEquals(new Integer(2), data.get("bbb"));
+ assertEquals(new Integer(3), data.get("zzz"));
+ Map developers = parsed.getDevelopers();
+ assertNotNull(developers);
+ assertEquals(2, developers.size());
+ Object o1 = developers.get("team1");
+ // because of erasure we get simply Map
+ Map<String, String> developer = (Map<String, String>) o1;
+ assertEquals("Fred", developer.get("name"));
+ assertEquals("creator", developer.get("role"));
+ }
+
+ @SuppressWarnings("rawtypes")
+ public static class MapBeanNoGenerics {
+ private Map data;
+ private String name;
+ private Map developers;
+
+ public MapBeanNoGenerics() {
+ name = "Bean123";
+ }
+
+ public Map getData() {
+ return data;
+ }
+
+ public void setData(Map data) {
+ this.data = data;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Map getDevelopers() {
+ return developers;
+ }
+
+ public void setDevelopers(Map developers) {
+ this.developers = developers;
+ }
+ }
+}
diff --git a/src/test/java/examples/collections/TypeSafePriorityTest.java b/src/test/java/examples/collections/TypeSafePriorityTest.java
new file mode 100644
index 0000000..bbe390d
--- /dev/null
+++ b/src/test/java/examples/collections/TypeSafePriorityTest.java
@@ -0,0 +1,118 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package examples.collections;
+
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.TypeDescription;
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.Constructor;
+
+/**
+ * Test ListBean->List<Human> developers <br/>
+ * Human is an interface and the global tags are required
+ */
+public class TypeSafePriorityTest extends TestCase {
+
+ /**
+ * explicit TypeDescription is more important then runtime class (which may
+ * be an interface)
+ */
+ public void testLoadList2() {
+ String output = Util.getLocalResource("examples/list-bean-3.yaml");
+ // System.out.println(output);
+ TypeDescription descr = new TypeDescription(ListBean.class);
+ descr.putListPropertyType("developers", Developer.class);
+ Yaml beanLoader = new Yaml(new Constructor(descr));
+ ListBean parsed = beanLoader.loadAs(output, ListBean.class);
+ assertNotNull(parsed);
+ List<Human> developers = parsed.getDevelopers();
+ assertEquals(2, developers.size());
+ assertEquals("Committer must be recognised.", Developer.class, developers.get(0).getClass());
+ Developer fred = (Developer) developers.get(0);
+ assertEquals("Fred", fred.getName());
+ assertEquals("creator", fred.getRole());
+ Developer john = (Developer) developers.get(1);
+ assertEquals("John", john.getName());
+ assertEquals("committer", john.getRole());
+ }
+
+ public static class ListBean {
+ private String name;
+ private List<Human> developers;
+
+ public ListBean() {
+ name = "Bean123";
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public List<Human> getDevelopers() {
+ return developers;
+ }
+
+ public void setDevelopers(List<Human> developers) {
+ this.developers = developers;
+ }
+ }
+
+ public static interface Human {
+
+ public String getName();
+
+ public void setName(String name);
+
+ }
+
+ public static class Developer implements Human {
+ private String name;
+ private String role;
+
+ public Developer() {
+ }
+
+ public Developer(String name, String role) {
+ this.name = name;
+ this.role = role;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getRole() {
+ return role;
+ }
+
+ public void setRole(String role) {
+ this.role = role;
+ }
+ }
+
+}
diff --git a/src/test/java/examples/collections/TypeSafeSetImplementationsTest.java b/src/test/java/examples/collections/TypeSafeSetImplementationsTest.java
new file mode 100644
index 0000000..297db14
--- /dev/null
+++ b/src/test/java/examples/collections/TypeSafeSetImplementationsTest.java
@@ -0,0 +1,270 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package examples.collections;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+
+/**
+ * Test different Map implementations as JavaBean properties
+ */
+public class TypeSafeSetImplementationsTest extends TestCase {
+ public void testDumpSet() {
+ SetBean bean = new SetBean();
+ SortedSet<String> sortedSet = new TreeSet<String>();
+ sortedSet.add("two");
+ sortedSet.add("one");
+ sortedSet.add("three");
+ bean.setSorted(sortedSet);
+ SortedSet<Developer> developers = new TreeSet<Developer>();
+ developers.add(new Developer("John", "founder"));
+ developers.add(new Developer("Karl", "user"));
+ bean.setDevelopers(developers);
+ Yaml yaml = new Yaml();
+ String output = yaml.dumpAsMap(bean);
+ // System.out.println(output);
+ String etalon = Util.getLocalResource("examples/set-bean-1.yaml");
+ assertEquals(etalon, output);
+ }
+
+ public void testDumpSet2() {
+ SetBean bean = new SetBean();
+ SortedSet<String> sortedSet = new TreeSet<String>();
+ sortedSet.add("two");
+ sortedSet.add("one");
+ sortedSet.add("three");
+ bean.setSorted(sortedSet);
+ SortedSet<Developer> developers = new TreeSet<Developer>();
+ developers.add(new Developer("John", "founder"));
+ developers.add(new Developer("Karl", "user"));
+ developers.add(new SuperDeveloper("Bill", "super"));
+ bean.setDevelopers(developers);
+ Yaml yaml = new Yaml();
+ String output = yaml.dumpAsMap(bean);
+ // System.out.println(output);
+ String etalon = Util.getLocalResource("examples/set-bean-6.yaml");
+ assertEquals(etalon, output);
+ }
+
+ public void testLoadSet() {
+ String output = Util.getLocalResource("examples/set-bean-1.yaml");
+ // System.out.println(output);
+ Yaml beanLoader = new Yaml();
+ SetBean parsed = beanLoader.loadAs(output, SetBean.class);
+ assertNotNull(parsed);
+ SortedSet<String> sortedMap = parsed.getSorted();
+ assertEquals(3, sortedMap.size());
+ assertTrue(sortedMap.contains("one"));
+ assertTrue(sortedMap.contains("two"));
+ assertTrue(sortedMap.contains("three"));
+ String first = sortedMap.iterator().next();
+ assertEquals("one", first);
+ //
+ SortedSet<Developer> developers = parsed.getDevelopers();
+ assertEquals(2, developers.size());
+ assertEquals("John", developers.first().getName());
+ assertEquals("Karl", developers.last().getName());
+ }
+
+ public void testLoadSetReversed() {
+ String output = Util.getLocalResource("examples/set-bean-2.yaml");
+ // System.out.println(output);
+ Yaml beanLoader = new Yaml();
+ SetBean parsed = beanLoader.loadAs(output, SetBean.class);
+ assertNotNull(parsed);
+ SortedSet<String> sortedMap = parsed.getSorted();
+ assertEquals(3, sortedMap.size());
+ assertTrue(sortedMap.contains("one"));
+ assertTrue(sortedMap.contains("two"));
+ assertTrue(sortedMap.contains("three"));
+ // alphabetically: one, three, two
+ assertEquals("one", sortedMap.first());
+ assertEquals("two", sortedMap.last());
+ // the order is not from YAML (must be sorted)
+ SortedSet<Developer> developers = parsed.getDevelopers();
+ assertEquals(2, developers.size());
+ assertEquals("John", developers.first().getName());
+ assertEquals("Karl", developers.last().getName());
+ }
+
+ public static class SetBean {
+ private SortedSet<String> sorted;
+ private SortedSet<Developer> developers;
+ private String name;
+
+ public SetBean() {
+ name = "Bean123";
+ }
+
+ public SortedSet<String> getSorted() {
+ return sorted;
+ }
+
+ public void setSorted(SortedSet<String> sorted) {
+ this.sorted = sorted;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public SortedSet<Developer> getDevelopers() {
+ return developers;
+ }
+
+ public void setDevelopers(SortedSet<Developer> developers) {
+ this.developers = developers;
+ }
+ }
+
+ public static class Developer implements Comparable<Developer> {
+ private String name;
+ private String role;
+
+ public Developer() {
+ }
+
+ public Developer(String name, String role) {
+ this.name = name;
+ this.role = role;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getRole() {
+ return role;
+ }
+
+ public void setRole(String role) {
+ this.role = role;
+ }
+
+ public int compareTo(Developer o) {
+ return name.compareTo(o.name);
+ }
+ }
+
+ public static class SuperDeveloper extends Developer {
+
+ public SuperDeveloper() {
+ super();
+ }
+
+ public SuperDeveloper(String string, String string2) {
+ super(string, string2);
+ }
+
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testNoJavaBeanSetRecursive() {
+ Set<Object> set = new HashSet<Object>(3);
+ set.add("aaa");
+ set.add(111);
+ Box box = new Box();
+ box.setId("id123");
+ box.setSet(set);
+ set.add(box);
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(set);
+ // System.out.println(output);
+ // the order may differ on different JVMs
+ // String etalon = Util.getLocalResource("examples/set-bean-3.yaml");
+ // assertEquals(etalon, output);
+ assertTrue(output.contains("&id001 !!set"));
+ assertTrue(output.contains("? !!examples.collections.TypeSafeSetImplementationsTest$Box"));
+ assertTrue(output.contains("set: *id001"));
+ assertTrue(output.contains("111: null"));
+ // load
+ Set<Object> list2 = (Set<Object>) yaml.load(output);
+ assertEquals(3, list2.size());
+ assertTrue(list2.contains("aaa"));
+ assertTrue(list2.contains(111));
+ }
+
+ public static class Box {
+ private String id;
+ private Set<Object> set;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public Set<Object> getSet() {
+ return set;
+ }
+
+ public void setSet(Set<Object> set) {
+ this.set = set;
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testNoJavaBeanSet() {
+ Yaml yaml = new Yaml();
+ String output = Util.getLocalResource("examples/set-bean-4.yaml");
+ // System.out.println(output);
+ // load
+ Set<String> set = (Set<String>) yaml.load(output);
+ assertEquals(3, set.size());
+ assertTrue(set.contains("aaa"));
+ assertTrue(set.contains("bbb"));
+ assertTrue(set.contains("zzz"));
+ Iterator<String> iter = set.iterator();
+ assertEquals("bbb", iter.next());
+ assertEquals("aaa", iter.next());
+ assertEquals("zzz", iter.next());
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testNoJavaBeanSet2() {
+ Yaml yaml = new Yaml();
+ String output = Util.getLocalResource("examples/set-bean-5.yaml");
+ // System.out.println(output);
+ // load and sort
+ Set<String> set = (Set<String>) yaml.load(output);
+ assertEquals(3, set.size());
+ assertTrue(set.contains("aaa"));
+ assertTrue(set.contains("bbb"));
+ assertTrue(set.contains("zzz"));
+ Iterator<String> iter = set.iterator();
+ assertEquals("aaa", iter.next());
+ assertEquals("bbb", iter.next());
+ assertEquals("zzz", iter.next());
+ }
+}
diff --git a/src/test/java/examples/jodatime/JodaTimeExampleTest.java b/src/test/java/examples/jodatime/JodaTimeExampleTest.java
new file mode 100644
index 0000000..0112608
--- /dev/null
+++ b/src/test/java/examples/jodatime/JodaTimeExampleTest.java
@@ -0,0 +1,120 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package examples.jodatime;
+
+import java.util.Date;
+
+import junit.framework.TestCase;
+
+import org.joda.time.DateMidnight;
+import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.AbstractConstruct;
+import org.yaml.snakeyaml.constructor.Construct;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.NodeId;
+import org.yaml.snakeyaml.nodes.Tag;
+
+public class JodaTimeExampleTest extends TestCase {
+ private static final long timestamp = 1000000000000L;
+
+ public void testDump() {
+ DateTime time = new DateTime(timestamp, DateTimeZone.UTC);
+ Yaml yaml = new Yaml(new JodaTimeRepresenter());
+ String joda = yaml.dump(time);
+ String date = new Yaml().dump(new Date(timestamp));
+ assertEquals(date, joda);
+ assertEquals("2001-09-09T01:46:40Z\n", joda);
+ }
+
+ public void testLoad() {
+ Yaml yaml = new Yaml(new JodaTimeImplicitContructor());
+ DateTime time = (DateTime) yaml.load("2001-09-09T01:46:40Z");
+ assertEquals(new DateTime(timestamp, DateTimeZone.UTC), time);
+ }
+
+ /**
+ * test issue 109
+ */
+ public void test109() {
+ Date someDate = new DateMidnight(9, 2, 21, DateTimeZone.forID("Europe/Amsterdam")).toDate();
+ Yaml yaml = new Yaml();
+ String timestamp = yaml.dump(someDate);
+ assertEquals("0009-02-22T23:40:28Z\n", timestamp);
+ // System.out.println(timestamp);
+ Object o = yaml.load(timestamp);
+ assertEquals(someDate, o);
+ }
+
+ class JodaPropertyConstructor extends Constructor {
+ public JodaPropertyConstructor() {
+ yamlClassConstructors.put(NodeId.scalar, new TimeStampConstruct());
+ }
+
+ class TimeStampConstruct extends Constructor.ConstructScalar {
+ @Override
+ public Object construct(Node nnode) {
+ if (nnode.getTag().equals("tag:yaml.org,2002:timestamp")) {
+ Construct dateConstructor = yamlConstructors.get(Tag.TIMESTAMP);
+ Date date = (Date) dateConstructor.construct(nnode);
+ return new DateTime(date, DateTimeZone.UTC);
+ } else {
+ return super.construct(nnode);
+ }
+ }
+ }
+ }
+
+ /**
+ * This class should be used if JodaTime may appear with a tag or as a
+ * JavaBean property
+ */
+ public class JodaTimeConstructor extends Constructor {
+ private final Construct javaDateConstruct;
+ private final Construct jodaDateConstruct;
+
+ public JodaTimeConstructor() {
+ javaDateConstruct = new ConstructYamlTimestamp();
+ jodaDateConstruct = new ConstructJodaTimestamp();
+ // Whenever we see an explicit timestamp tag, make a Joda Date
+ // instead
+ yamlConstructors.put(Tag.TIMESTAMP, jodaDateConstruct);
+ // See
+ // We need this to work around implicit construction.
+ yamlClassConstructors.put(NodeId.scalar, new TimeStampConstruct());
+ }
+
+ public class ConstructJodaTimestamp extends AbstractConstruct {
+ public Object construct(Node node) {
+ Date date = (Date) javaDateConstruct.construct(node);
+ return new DateTime(date, DateTimeZone.UTC);
+ }
+ }
+
+ class TimeStampConstruct extends Constructor.ConstructScalar {
+ @Override
+ public Object construct(Node nnode) {
+ if (nnode.getTag().equals(Tag.TIMESTAMP)) {
+ return jodaDateConstruct.construct(nnode);
+ } else {
+ return super.construct(nnode);
+ }
+ }
+ }
+ }
+}
diff --git a/src/test/java/examples/jodatime/JodaTimeFlowStylesTest.java b/src/test/java/examples/jodatime/JodaTimeFlowStylesTest.java
new file mode 100644
index 0000000..901385a
--- /dev/null
+++ b/src/test/java/examples/jodatime/JodaTimeFlowStylesTest.java
@@ -0,0 +1,154 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package examples.jodatime;
+
+import java.util.Date;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.DumperOptions.FlowStyle;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.Construct;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.events.Event;
+import org.yaml.snakeyaml.events.ScalarEvent;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.NodeId;
+import org.yaml.snakeyaml.nodes.Tag;
+
+public class JodaTimeFlowStylesTest extends TestCase {
+ private static final long timestamp = 1000000000000L;
+
+ /**
+ * @see <a href="http://code.google.com/p/snakeyaml/issues/detail?id=128"></a>
+ */
+ public void testLoadBeanWithBlockFlow() {
+ MyBean bean = new MyBean();
+ bean.setId("id123");
+ DateTime etalon = new DateTime(timestamp, DateTimeZone.UTC);
+ bean.setDate(etalon);
+ DumperOptions options = new DumperOptions();
+ options.setDefaultFlowStyle(FlowStyle.BLOCK);
+ Yaml dumper = new Yaml(new JodaTimeRepresenter(), options);
+ // compare Nodes with flow style AUTO and flow style BLOCK
+ Node node1 = dumper.represent(bean);
+ DumperOptions options2 = new DumperOptions();
+ options2.setDefaultFlowStyle(FlowStyle.AUTO);
+ Yaml dumper2 = new Yaml(new JodaTimeRepresenter(), options2);
+ Node node2 = dumper2.represent(bean);
+ assertEquals(node2.toString(), node1.toString());
+ // compare Events with flow style AUTO and flow style BLOCK
+ List<Event> events1 = dumper.serialize(node1);
+ List<Event> events2 = dumper2.serialize(node2);
+ assertEquals(events2.size(), events1.size());
+ int i = 0;
+ for (Event etalonEvent : events2) {
+ assertEquals(etalonEvent, events1.get(i++));
+ if (etalonEvent instanceof ScalarEvent) {
+ ScalarEvent scalar = (ScalarEvent) etalonEvent;
+ if (scalar.getValue().equals("2001-09-09T01:46:40Z")) {
+ assertTrue(scalar.getImplicit().canOmitTagInPlainScalar());
+ assertFalse(scalar.getImplicit().canOmitTagInNonPlainScalar());
+ }
+ }
+ }
+ // Nodes and Events are the same. Only emitter may influence the output.
+ String doc1 = dumper.dump(bean);
+ // System.out.println(doc1);
+ /*
+ * 'date' must be used only with the explicit '!!timestamp' tag.
+ * Implicit tag will not work because 'date' is the JavaBean property
+ * and in this case the empty constructor of the class will be used.
+ * Since this constructor does not exist for JodaTime an exception will
+ * be thrown.
+ */
+ assertEquals("!!examples.jodatime.MyBean\ndate: 2001-09-09T01:46:40Z\nid: id123\n", doc1);
+ /*
+ * provided JodaTimeContructor will be ignored because 'date' is a
+ * JavaBean property and its class gets more priority then the implicit
+ * '!!timestamp' tag.
+ */
+ Yaml loader = new Yaml(new JodaTimeImplicitContructor());
+ try {
+ loader.load(doc1);
+ } catch (Exception e) {
+ assertTrue(
+ "The error must indicate that JodaTime cannot be created from the scalar value.",
+ e.getMessage()
+ .contains(
+ "No String constructor found. Exception=org.joda.time.DateTime.<init>(java.lang.String)"));
+ }
+ // we have to provide a special way to create JodaTime instances from
+ // scalars
+ Yaml loader2 = new Yaml(new JodaPropertyConstructor());
+ MyBean parsed = (MyBean) loader2.load(doc1);
+ assertEquals(etalon, parsed.getDate());
+ }
+
+ /**
+ * !!timestamp must be used, without it the implicit tag will be ignored
+ * because 'date' is the JavaBean property.
+ *
+ * Since the timestamp contains ':' character it cannot use plain scalar
+ * style in the FLOW mapping style. Emitter suggests single quoted scalar
+ * style and that is why the explicit '!!timestamp' is present in the YAML
+ * document.
+ *
+ * @see <a href="http://code.google.com/p/snakeyaml/issues/detail?id=128"></a>
+ *
+ */
+ public void testLoadBeanWithAutoFlow() {
+ MyBean bean = new MyBean();
+ bean.setId("id123");
+ DateTime etalon = new DateTime(timestamp, DateTimeZone.UTC);
+ bean.setDate(etalon);
+ DumperOptions options = new DumperOptions();
+ options.setDefaultFlowStyle(FlowStyle.AUTO);
+ Yaml dumper = new Yaml(new JodaTimeRepresenter(), options);
+ String doc = dumper.dump(bean);
+ // System.out.println(doc);
+ assertEquals(
+ "!!examples.jodatime.MyBean {date: !!timestamp '2001-09-09T01:46:40Z', id: id123}\n",
+ doc);
+ Yaml loader = new Yaml(new JodaTimeImplicitContructor());
+ MyBean parsed = (MyBean) loader.load(doc);
+ assertEquals(etalon, parsed.getDate());
+ }
+
+ private class JodaPropertyConstructor extends Constructor {
+ public JodaPropertyConstructor() {
+ yamlClassConstructors.put(NodeId.scalar, new TimeStampConstruct());
+ }
+
+ class TimeStampConstruct extends Constructor.ConstructScalar {
+ @Override
+ public Object construct(Node nnode) {
+ if (nnode.getTag().equals(new Tag("tag:yaml.org,2002:timestamp"))) {
+ Construct dateConstructor = yamlConstructors.get(Tag.TIMESTAMP);
+ Date date = (Date) dateConstructor.construct(nnode);
+ return new DateTime(date, DateTimeZone.UTC);
+ } else {
+ return super.construct(nnode);
+ }
+ }
+
+ }
+ }
+}
diff --git a/src/test/java/examples/jodatime/JodaTimeImplicitContructor.java b/src/test/java/examples/jodatime/JodaTimeImplicitContructor.java
new file mode 100644
index 0000000..e1af428
--- /dev/null
+++ b/src/test/java/examples/jodatime/JodaTimeImplicitContructor.java
@@ -0,0 +1,40 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package examples.jodatime;
+
+import java.util.Date;
+
+import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.Tag;
+
+/**
+ * It works only when JodaTime is not a JavaBean property
+ */
+public class JodaTimeImplicitContructor extends Constructor {
+ public JodaTimeImplicitContructor() {
+ this.yamlConstructors.put(Tag.TIMESTAMP, new ConstructJodaTimestamp());
+ }
+
+ private class ConstructJodaTimestamp extends ConstructYamlTimestamp {
+ public Object construct(Node node) {
+ Date date = (Date) super.construct(node);
+ return new DateTime(date, DateTimeZone.UTC);
+ }
+ }
+}
diff --git a/src/test/java/examples/jodatime/JodaTimeRepresenter.java b/src/test/java/examples/jodatime/JodaTimeRepresenter.java
new file mode 100644
index 0000000..f7fd824
--- /dev/null
+++ b/src/test/java/examples/jodatime/JodaTimeRepresenter.java
@@ -0,0 +1,36 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package examples.jodatime;
+
+import java.util.Date;
+
+import org.joda.time.DateTime;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.representer.Representer;
+
+class JodaTimeRepresenter extends Representer {
+ public JodaTimeRepresenter() {
+ multiRepresenters.put(DateTime.class, new RepresentJodaDateTime());
+ }
+
+ private class RepresentJodaDateTime extends RepresentDate {
+
+ public Node representData(Object data) {
+ DateTime date = (DateTime) data;
+ return super.representData(new Date(date.getMillis()));
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/examples/jodatime/MyBean.java b/src/test/java/examples/jodatime/MyBean.java
new file mode 100644
index 0000000..5957ae5
--- /dev/null
+++ b/src/test/java/examples/jodatime/MyBean.java
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package examples.jodatime;
+
+import org.joda.time.DateTime;
+
+public class MyBean {
+ private String id;
+ private DateTime date;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public DateTime getDate() {
+ return date;
+ }
+
+ public void setDate(DateTime date) {
+ this.date = date;
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/examples/resolver/CustomIntResolver.java b/src/test/java/examples/resolver/CustomIntResolver.java
new file mode 100644
index 0000000..5244b1a
--- /dev/null
+++ b/src/test/java/examples/resolver/CustomIntResolver.java
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package examples.resolver;
+
+import java.util.regex.Pattern;
+
+import org.yaml.snakeyaml.nodes.Tag;
+import org.yaml.snakeyaml.resolver.Resolver;
+
+public class CustomIntResolver extends Resolver {
+ public static final Pattern PURE_INT = Pattern.compile("^[0-9]+$");
+
+ /*
+ * do not resolve int if it has underscores
+ */
+ protected void addImplicitResolvers() {
+ addImplicitResolver(Tag.BOOL, BOOL, "yYnNtTfFoO");
+ addImplicitResolver(Tag.FLOAT, FLOAT, "-+0123456789.");
+ // define simple int pattern
+ addImplicitResolver(Tag.INT, PURE_INT, "0123456789");
+ addImplicitResolver(Tag.MERGE, MERGE, "<");
+ addImplicitResolver(Tag.NULL, NULL, "~nN\0");
+ addImplicitResolver(Tag.NULL, EMPTY, null);
+ addImplicitResolver(Tag.TIMESTAMP, TIMESTAMP, "0123456789");
+ }
+}
diff --git a/src/test/java/examples/resolver/CustomResolver.java b/src/test/java/examples/resolver/CustomResolver.java
new file mode 100644
index 0000000..4e3f71c
--- /dev/null
+++ b/src/test/java/examples/resolver/CustomResolver.java
@@ -0,0 +1,35 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package examples.resolver;
+
+import org.yaml.snakeyaml.nodes.Tag;
+import org.yaml.snakeyaml.resolver.Resolver;
+
+public class CustomResolver extends Resolver {
+
+ /*
+ * do not resolve float and timestamp
+ */
+ protected void addImplicitResolvers() {
+ addImplicitResolver(Tag.BOOL, BOOL, "yYnNtTfFoO");
+ // addImplicitResolver(Tags.FLOAT, FLOAT, "-+0123456789.");
+ addImplicitResolver(Tag.INT, INT, "-+0123456789");
+ addImplicitResolver(Tag.MERGE, MERGE, "<");
+ addImplicitResolver(Tag.NULL, NULL, "~nN\0");
+ addImplicitResolver(Tag.NULL, EMPTY, null);
+ // addImplicitResolver(Tags.TIMESTAMP, TIMESTAMP, "0123456789");
+ }
+}
diff --git a/src/test/java/examples/resolver/CustomResolverTest.java b/src/test/java/examples/resolver/CustomResolverTest.java
new file mode 100644
index 0000000..e647a25
--- /dev/null
+++ b/src/test/java/examples/resolver/CustomResolverTest.java
@@ -0,0 +1,56 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package examples.resolver;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.representer.Representer;
+
+public class CustomResolverTest extends TestCase {
+
+ public void testResolverToDump() {
+ Map<Object, Object> map = new HashMap<Object, Object>();
+ map.put("1.0", "2009-01-01");
+ Yaml yaml = new Yaml(new Constructor(), new Representer(), new DumperOptions(),
+ new CustomResolver());
+ String output = yaml.dump(map);
+ assertEquals("{1.0: 2009-01-01}\n", output);
+ assertEquals("Float and Date must be escaped.", "{'1.0': '2009-01-01'}\n",
+ new Yaml().dump(map));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testResolverToLoad() {
+ Yaml yaml = new Yaml(new Constructor(), new Representer(), new DumperOptions(),
+ new CustomResolver());
+ Map<Object, Object> map = (Map<Object, Object>) yaml.load("1.0: 2009-01-01");
+ assertEquals(1, map.size());
+ assertEquals("2009-01-01", map.get("1.0"));
+ // the default Resolver shall create Date and Double from the same YAML
+ // document
+ Yaml yaml2 = new Yaml();
+ Map<Object, Object> map2 = (Map<Object, Object>) yaml2.load("1.0: 2009-01-01");
+ assertEquals(1, map2.size());
+ assertFalse(map2.containsKey("1.0"));
+ assertTrue(map2.toString(), map2.containsKey(new Double(1.0)));
+ }
+}
diff --git a/src/test/java/examples/staticstate/JavaBeanWithStaticState.java b/src/test/java/examples/staticstate/JavaBeanWithStaticState.java
new file mode 100644
index 0000000..0514de0
--- /dev/null
+++ b/src/test/java/examples/staticstate/JavaBeanWithStaticState.java
@@ -0,0 +1,47 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package examples.staticstate;
+
+public class JavaBeanWithStaticState {
+ private String name;
+ private int age;
+ public static String color;// public field
+ private static String type;// private field with a getter
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public int getAge() {
+ return age;
+ }
+
+ public void setAge(int age) {
+ this.age = age;
+ }
+
+ public static String getType() {
+ return type;
+ }
+
+ public static void setType(String type) {
+ JavaBeanWithStaticState.type = type;
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/examples/staticstate/StaticFieldsTest.java b/src/test/java/examples/staticstate/StaticFieldsTest.java
new file mode 100644
index 0000000..60068ce
--- /dev/null
+++ b/src/test/java/examples/staticstate/StaticFieldsTest.java
@@ -0,0 +1,121 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package examples.staticstate;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.introspector.Property;
+import org.yaml.snakeyaml.nodes.MappingNode;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.NodeTuple;
+import org.yaml.snakeyaml.nodes.ScalarNode;
+import org.yaml.snakeyaml.representer.Representer;
+
+/**
+ * Example with static fields
+ */
+public class StaticFieldsTest extends TestCase {
+ public void testAsJavaBean() {
+ JavaBeanWithStaticState bean = new JavaBeanWithStaticState();
+ bean.setName("Bahrack");
+ bean.setAge(-47);
+ JavaBeanWithStaticState.setType("Represent");
+ JavaBeanWithStaticState.color = "Black";
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(bean);
+ // System.out.println(output);
+ assertEquals("!!examples.staticstate.JavaBeanWithStaticState {age: -47, name: Bahrack}\n",
+ output);
+ // parse back to instance
+ JavaBeanWithStaticState bean2 = (JavaBeanWithStaticState) yaml.load(output);
+ assertEquals(-47, bean2.getAge());
+ assertEquals("Bahrack", bean2.getName());
+ }
+
+ public void testCustomDump() {
+ JavaBeanWithStaticState bean = new JavaBeanWithStaticState();
+ bean.setName("Lui");
+ bean.setAge(25);
+ JavaBeanWithStaticState.setType("Represent");
+ JavaBeanWithStaticState.color = "Black";
+ Yaml yaml = new Yaml(new MyRepresenter(), new DumperOptions());
+ String output = yaml.dump(bean);
+ // System.out.println(output);
+ assertEquals(
+ "!!examples.staticstate.JavaBeanWithStaticState {age: 25, name: Lui, color: Black,\n type: Represent}\n",
+ output);
+ }
+
+ public void testCustomLoad() {
+ Yaml yaml = new Yaml(new MyConstructor());
+ String output = "!!examples.staticstate.JavaBeanWithStaticState {age: 25, name: Lui, color: Oranje,\n type: King}\n";
+ JavaBeanWithStaticState bean2 = (JavaBeanWithStaticState) yaml.load(output);
+ assertEquals(25, bean2.getAge());
+ assertEquals("Lui", bean2.getName());
+ assertEquals("Oranje", JavaBeanWithStaticState.color);
+ assertEquals("King", JavaBeanWithStaticState.getType());
+ }
+
+ private class MyRepresenter extends Representer {
+ @Override
+ protected MappingNode representJavaBean(Set<Property> properties, Object javaBean) {
+ MappingNode node = super.representJavaBean(properties, javaBean);
+ if (javaBean instanceof JavaBeanWithStaticState) {
+ List<NodeTuple> value = node.getValue();
+ value.add(new NodeTuple(representData("color"),
+ representData(JavaBeanWithStaticState.color)));
+ value.add(new NodeTuple(representData("type"),
+ representData(JavaBeanWithStaticState.getType())));
+ }
+ return node;
+ }
+ }
+
+ private class MyConstructor extends Constructor {
+ protected Object constructObject(Node node) {
+ if (node.getType().isAssignableFrom(JavaBeanWithStaticState.class)) {
+ MappingNode beanNode = (MappingNode) node;
+ List<NodeTuple> value = beanNode.getValue();
+ List<NodeTuple> removed = new ArrayList<NodeTuple>();
+ for (NodeTuple tuple : value) {
+ ScalarNode keyNode = (ScalarNode) tuple.getKeyNode();
+ if (keyNode.getValue().equals("color")) {
+ ScalarNode valueNode = (ScalarNode) tuple.getValueNode();
+ JavaBeanWithStaticState.color = valueNode.getValue();
+ } else if (keyNode.getValue().equals("type")) {
+ ScalarNode valueNode = (ScalarNode) tuple.getValueNode();
+ JavaBeanWithStaticState.setType(valueNode.getValue());
+ } else
+ removed.add(tuple);
+ }
+ beanNode.setValue(removed);
+ JavaBeanWithStaticState bean = (JavaBeanWithStaticState) super
+ .constructObject(beanNode);
+
+ return bean;
+ } else {
+ return super.constructObject(node);
+ }
+ }
+ }
+}
diff --git a/src/test/java/examples/staticstate/StaticFieldsWrapperTest.java b/src/test/java/examples/staticstate/StaticFieldsWrapperTest.java
new file mode 100644
index 0000000..7555258
--- /dev/null
+++ b/src/test/java/examples/staticstate/StaticFieldsWrapperTest.java
@@ -0,0 +1,100 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package examples.staticstate;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.TypeDescription;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.nodes.Tag;
+import org.yaml.snakeyaml.representer.Representer;
+
+/**
+ * Example: using wrapper object for static fields
+ */
+public class StaticFieldsWrapperTest extends TestCase {
+
+ /**
+ * use wrapper with global tag
+ */
+ public void testWrapper() {
+ JavaBeanWithStaticState bean = new JavaBeanWithStaticState();
+ bean.setName("Bahrack");
+ bean.setAge(-47);
+ JavaBeanWithStaticState.setType("Type3");
+ JavaBeanWithStaticState.color = "Violet";
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(new Wrapper(bean));
+ // System.out.println(output);
+ assertEquals(
+ "!!examples.staticstate.Wrapper {age: -47, color: Violet, name: Bahrack, type: Type3}\n",
+ output);
+ // parse back to instance
+ Wrapper wrapper = (Wrapper) yaml.load(output);
+ JavaBeanWithStaticState bean2 = wrapper.createBean();
+ assertEquals(-47, bean2.getAge());
+ assertEquals("Bahrack", bean2.getName());
+ }
+
+ /**
+ * use wrapper with local tag
+ */
+ public void testLocalTag() {
+ JavaBeanWithStaticState bean = new JavaBeanWithStaticState();
+ bean.setName("Bahrack");
+ bean.setAge(-47);
+ JavaBeanWithStaticState.setType("Type3");
+ JavaBeanWithStaticState.color = "Violet";
+ Representer repr = new Representer();
+ repr.addClassTag(Wrapper.class, new Tag("!mybean"));
+ Yaml yaml = new Yaml(repr);
+ String output = yaml.dump(new Wrapper(bean));
+ // System.out.println(output);
+ assertEquals("!mybean {age: -47, color: Violet, name: Bahrack, type: Type3}\n", output);
+ // parse back to instance
+ Constructor constr = new Constructor();
+ TypeDescription description = new TypeDescription(Wrapper.class, new Tag("!mybean"));
+ constr.addTypeDescription(description);
+ yaml = new Yaml(constr);
+ Wrapper wrapper = (Wrapper) yaml.load(output);
+ JavaBeanWithStaticState bean2 = wrapper.createBean();
+ assertEquals(-47, bean2.getAge());
+ assertEquals("Bahrack", bean2.getName());
+ }
+
+ /**
+ * use wrapper with no tag
+ */
+ public void testRootBean() {
+ JavaBeanWithStaticState bean = new JavaBeanWithStaticState();
+ bean.setName("Bahrack");
+ bean.setAge(-47);
+ JavaBeanWithStaticState.setType("Type3");
+ JavaBeanWithStaticState.color = "Violet";
+ Yaml yaml = new Yaml();
+ String output = yaml.dumpAsMap(new Wrapper(bean));
+ // System.out.println(output);
+ assertEquals("age: -47\ncolor: Violet\nname: Bahrack\ntype: Type3\n", output);
+ // parse back to instance
+ Yaml loader = new Yaml();
+ Wrapper wrapper = loader.loadAs(output, Wrapper.class);
+ JavaBeanWithStaticState bean2 = wrapper.createBean();
+ assertEquals(-47, bean2.getAge());
+ assertEquals("Bahrack", bean2.getName());
+ }
+
+}
diff --git a/src/test/java/examples/staticstate/Wrapper.java b/src/test/java/examples/staticstate/Wrapper.java
new file mode 100644
index 0000000..b5c5bbb
--- /dev/null
+++ b/src/test/java/examples/staticstate/Wrapper.java
@@ -0,0 +1,75 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package examples.staticstate;
+
+public class Wrapper {
+ private String name;
+ private int age;
+ private String color;
+ private String type;
+
+ public JavaBeanWithStaticState createBean() {
+ JavaBeanWithStaticState bean = new JavaBeanWithStaticState();
+ bean.setAge(age);
+ bean.setName(name);
+ JavaBeanWithStaticState.color = color;
+ JavaBeanWithStaticState.setType(type);
+ return bean;
+ }
+
+ public Wrapper() {
+ color = JavaBeanWithStaticState.color;
+ type = JavaBeanWithStaticState.getType();
+ }
+
+ public Wrapper(JavaBeanWithStaticState bean) {
+ this();
+ name = bean.getName();
+ age = bean.getAge();
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public int getAge() {
+ return age;
+ }
+
+ public void setAge(int age) {
+ this.age = age;
+ }
+
+ public String getColor() {
+ return color;
+ }
+
+ public void setColor(String color) {
+ this.color = color;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+}
\ 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 0000000..ddff4f1
--- /dev/null
+++ b/src/test/java/org/pyyaml/AnInstance.java
@@ -0,0 +1,45 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+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 0000000..3eedb88
--- /dev/null
+++ b/src/test/java/org/pyyaml/CanonicalException.java
@@ -0,0 +1,31 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+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 0000000..e2d0444
--- /dev/null
+++ b/src/test/java/org/pyyaml/CanonicalLoader.java
@@ -0,0 +1,85 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.pyyaml;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.util.Iterator;
+
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.composer.Composer;
+import org.yaml.snakeyaml.error.YAMLException;
+
+public class CanonicalLoader extends Yaml {
+ @Override
+ public Object load(Reader yaml) {
+ try {
+ int ch = yaml.read();
+ StringBuilder buffer = new StringBuilder();
+ 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(Object.class);
+ } catch (IOException e) {
+ throw new YAMLException(e);
+ }
+ }
+
+ public Iterable<Object> loadAll(Reader yaml) {
+ try {
+ int ch = yaml.read();
+ StringBuilder buffer = new StringBuilder();
+ 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 0000000..eccd964
--- /dev/null
+++ b/src/test/java/org/pyyaml/CanonicalParser.java
@@ -0,0 +1,190 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.pyyaml;
+
+import java.util.ArrayList;
+
+import org.yaml.snakeyaml.DumperOptions.Version;
+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.ImplicitTuple;
+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.ScalarToken;
+import org.yaml.snakeyaml.tokens.TagToken;
+import org.yaml.snakeyaml.tokens.Token;
+
+public class CanonicalParser implements Parser {
+ private ArrayList<Event> events;
+ private boolean parsed;
+ private CanonicalScanner scanner;
+
+ public CanonicalParser(String data) {
+ events = new ArrayList<Event>();
+ parsed = false;
+ scanner = new CanonicalScanner(data);
+ }
+
+ // stream: STREAM-START document* STREAM-END
+ private void parseStream() {
+ scanner.getToken(Token.ID.StreamStart);
+ events.add(new StreamStartEvent(null, null));
+ while (!scanner.checkToken(Token.ID.StreamEnd)) {
+ if (scanner.checkToken(Token.ID.Directive, Token.ID.DocumentStart)) {
+ parseDocument();
+ } else {
+ throw new CanonicalException("document is expected, got " + scanner.tokens.get(0));
+ }
+ }
+ scanner.getToken(Token.ID.StreamEnd);
+ events.add(new StreamEndEvent(null, null));
+ }
+
+ // document: DIRECTIVE? DOCUMENT-START node
+ private void parseDocument() {
+ if (scanner.checkToken(Token.ID.Directive)) {
+ scanner.getToken(Token.ID.Directive);
+ }
+ scanner.getToken(Token.ID.DocumentStart);
+ events.add(new DocumentStartEvent(null, null, true, Version.V1_1, null));
+ parseNode();
+ events.add(new DocumentEndEvent(null, null, true));
+ }
+
+ // node: ALIAS | ANCHOR? TAG? (SCALAR|sequence|mapping)
+ private void parseNode() {
+ if (scanner.checkToken(Token.ID.Alias)) {
+ AliasToken token = (AliasToken) scanner.getToken();
+ events.add(new AliasEvent(token.getValue(), null, null));
+ } else {
+ String anchor = null;
+ if (scanner.checkToken(Token.ID.Anchor)) {
+ AnchorToken token = (AnchorToken) scanner.getToken();
+ anchor = token.getValue();
+ }
+ String tag = null;
+ if (scanner.checkToken(Token.ID.Tag)) {
+ TagToken token = (TagToken) scanner.getToken();
+ tag = token.getValue().getHandle() + token.getValue().getSuffix();
+ }
+ if (scanner.checkToken(Token.ID.Scalar)) {
+ ScalarToken token = (ScalarToken) scanner.getToken();
+ events.add(new ScalarEvent(anchor, tag, new ImplicitTuple(false, false), token
+ .getValue(), null, null, null));
+ } else if (scanner.checkToken(Token.ID.FlowSequenceStart)) {
+ events.add(new SequenceStartEvent(anchor, tag, false, null, null, null));
+ parseSequence();
+ } else if (scanner.checkToken(Token.ID.FlowMappingStart)) {
+ 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(Token.ID.FlowSequenceStart);
+ if (!scanner.checkToken(Token.ID.FlowSequenceEnd)) {
+ parseNode();
+ while (!scanner.checkToken(Token.ID.FlowSequenceEnd)) {
+ scanner.getToken(Token.ID.FlowEntry);
+ if (!scanner.checkToken(Token.ID.FlowSequenceEnd)) {
+ parseNode();
+ }
+ }
+ }
+ scanner.getToken(Token.ID.FlowSequenceEnd);
+ events.add(new SequenceEndEvent(null, null));
+ }
+
+ // mapping: MAPPING-START (map_entry (ENTRY map_entry)*)? ENTRY? MAPPING-END
+ private void parseMapping() {
+ scanner.getToken(Token.ID.FlowMappingStart);
+ if (!scanner.checkToken(Token.ID.FlowMappingEnd)) {
+ parseMapEntry();
+ while (!scanner.checkToken(Token.ID.FlowMappingEnd)) {
+ scanner.getToken(Token.ID.FlowEntry);
+ if (!scanner.checkToken(Token.ID.FlowMappingEnd)) {
+ parseMapEntry();
+ }
+ }
+ }
+ scanner.getToken(Token.ID.FlowMappingEnd);
+ events.add(new MappingEndEvent(null, null));
+ }
+
+ // map_entry: KEY node VALUE node
+ private void parseMapEntry() {
+ scanner.getToken(Token.ID.Key);
+ parseNode();
+ scanner.getToken(Token.ID.Value);
+ parseNode();
+ }
+
+ public void parse() {
+ parseStream();
+ parsed = true;
+ }
+
+ public Event getEvent() {
+ if (!parsed) {
+ parse();
+ }
+ return events.remove(0);
+ }
+
+ /**
+ * Check the type of the next event.
+ */
+ public boolean checkEvent(Event.ID choice) {
+ if (!parsed) {
+ parse();
+ }
+ if (!events.isEmpty()) {
+ if (events.get(0).is(choice)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Get the next event.
+ */
+ 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 0000000..0bb8cc6
--- /dev/null
+++ b/src/test/java/org/pyyaml/CanonicalScanner.java
@@ -0,0 +1,306 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.pyyaml;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.yaml.snakeyaml.error.Mark;
+import org.yaml.snakeyaml.nodes.Tag;
+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.TagTuple;
+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 ArrayList<Token> tokens;
+ private boolean scanned;
+ private Mark mark;
+
+ public CanonicalScanner(String data) {
+ this.data = data + "\0";
+ this.index = 0;
+ this.tokens = new ArrayList<Token>();
+ this.scanned = false;
+ this.mark = new Mark("test", 0, 0, 0, data, 0);
+ }
+
+ public boolean checkToken(Token.ID... choices) {
+ if (!scanned) {
+ scan();
+ }
+ if (!tokens.isEmpty()) {
+ if (choices.length == 0) {
+ return true;
+ }
+ Token first = this.tokens.get(0);
+ for (Token.ID choice : choices) {
+ if (first.getTokenId() == choice) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public Token peekToken() {
+ if (!scanned) {
+ scan();
+ }
+ if (!tokens.isEmpty()) {
+ return this.tokens.get(0);
+ }
+ return null;
+ }
+
+ public Token getToken() {
+ if (!scanned) {
+ scan();
+ }
+ return this.tokens.remove(0);
+ }
+
+ public Token getToken(Token.ID choice) {
+ Token token = getToken();
+ if (choice != null && token.getTokenId() != choice) {
+ 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<Integer>("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.PREFIX + 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 TagTuple("", value), mark, mark);
+ }
+
+ private Token scanScalar() {
+ index++;
+ StringBuilder chunks = new StringBuilder();
+ 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 0000000..fc6a9e3
--- /dev/null
+++ b/src/test/java/org/pyyaml/PyCanonicalTest.java
@@ -0,0 +1,69 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.pyyaml;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.yaml.snakeyaml.events.Event;
+import org.yaml.snakeyaml.tokens.Token;
+
+/**
+ * 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++) {
+ InputStream input = new FileInputStream(files[i]);
+ List<Token> tokens = canonicalScan(input);
+ input.close();
+ assertFalse(tokens.isEmpty());
+ }
+ }
+
+ private List<Token> canonicalScan(InputStream input) throws IOException {
+ int ch = input.read();
+ StringBuilder buffer = new StringBuilder();
+ while (ch != -1) {
+ buffer.append((char) ch);
+ ch = input.read();
+ }
+ CanonicalScanner scanner = new CanonicalScanner(buffer.toString());
+ List<Token> result = new ArrayList<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++) {
+ InputStream input = new FileInputStream(files[i]);
+ List<Event> tokens = canonicalParse(input);
+ input.close();
+ 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 0000000..8ca80d3
--- /dev/null
+++ b/src/test/java/org/pyyaml/PyEmitterTest.java
@@ -0,0 +1,292 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.pyyaml;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.emitter.Emitter;
+import org.yaml.snakeyaml.emitter.EventConstructor;
+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.StreamReader;
+import org.yaml.snakeyaml.reader.UnicodeReader;
+
+/**
+ * imported from PyYAML
+ */
+public class PyEmitterTest extends PyImportTest {
+ public void testEmitterOnData() {
+ _testEmitter(".data", false);
+ }
+
+ public void testEmitterOnCanonicalNormally() {
+ _testEmitter(".canonical", false);
+ }
+
+ public void testEmitterOnCanonicalCanonically() {
+ _testEmitter(".canonical", true);
+ }
+
+ private void _testEmitter(String mask, boolean canonical) {
+ 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 {
+ InputStream input = new FileInputStream(file);
+ List<Event> events = parse(input);
+ input.close();
+ //
+ 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 ArrayList<Event>();
+ StreamReader reader = new StreamReader(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;
+ if (e1.getImplicit().bothFalse() && e2.getImplicit().bothFalse()) {
+ 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);
+ }
+ }
+ }
+
+ public void testEmitterStyles() {
+ 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 ArrayList<File>(Arrays.asList(canonicalFiles));
+ allFiles.addAll(Arrays.asList(dataFiles));
+ for (File file : allFiles) {
+ try {
+ List<Event> events = new ArrayList<Event>();
+ InputStream input = new FileInputStream(file);
+ StreamReader reader = new StreamReader(new UnicodeReader(input));
+ Parser parser = new ParserImpl(reader);
+ while (parser.peekEvent() != null) {
+ Event event = parser.getEvent();
+ events.add(event);
+ }
+ input.close();
+ //
+ for (Boolean flowStyle : new Boolean[] { Boolean.FALSE, Boolean.TRUE }) {
+ for (DumperOptions.ScalarStyle style : DumperOptions.ScalarStyle.values()) {
+ List<Event> styledEvents = new ArrayList<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;
+ if (scalarOld.getImplicit().bothFalse()
+ && scalarNew.getImplicit().bothFalse()) {
+ 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 StreamReader(data));
+ List<Event> newEvents = new ArrayList<Event>();
+ while (parser.peekEvent() != null) {
+ newEvents.add(parser.getEvent());
+ }
+ return newEvents;
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testEmitterEvents() {
+ 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 {
+ List<Event> events = new ArrayList<Event>();
+ String content = getResource(file.getName());
+ events = (List<Event>) load(new EventConstructor(), 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 ArrayList<Event>();
+ StreamReader reader = new StreamReader(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;
+ if (e1.getImplicit().canOmitTagInPlainScalar() == e2.getImplicit()
+ .canOmitTagInPlainScalar()
+ && e1.getImplicit().canOmitTagInNonPlainScalar() == e2
+ .getImplicit().canOmitTagInNonPlainScalar()) {
+
+ } 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 0000000..1495584
--- /dev/null
+++ b/src/test/java/org/pyyaml/PyErrorsTest.java
@@ -0,0 +1,131 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.pyyaml;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+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.emitter.Emitter;
+import org.yaml.snakeyaml.emitter.EventConstructor;
+import org.yaml.snakeyaml.error.YAMLException;
+import org.yaml.snakeyaml.events.Event;
+
+/**
+ * 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 {
+ InputStream input = new FileInputStream(files[i]);
+ for (Object document : loadAll(input)) {
+ assertNotNull("File " + files[i], document);
+ }
+ input.close();
+ 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++) {
+ String content = getResource(files[i].getName());
+ List<Event> document = (List<Event>) load(new EventConstructor(), 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 0000000..966e5e7
--- /dev/null
+++ b/src/test/java/org/pyyaml/PyImportTest.java
@@ -0,0 +1,135 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.pyyaml;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.events.Event;
+import org.yaml.snakeyaml.parser.Parser;
+import org.yaml.snakeyaml.parser.ParserImpl;
+import org.yaml.snakeyaml.reader.StreamReader;
+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();
+ return yaml.load(data);
+ }
+
+ protected Object load(Constructor loader, String data) {
+ Yaml yaml = new Yaml(loader);
+ return yaml.load(data);
+ }
+
+ 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(Constructor loader, String data) {
+ Yaml yaml = new Yaml(loader);
+ return yaml.loadAll(data);
+ }
+
+ protected String getResource(String theName) {
+ String content;
+ content = Util.getLocalResource(PATH + File.separator + theName);
+ return content;
+ }
+
+ 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());
+ return file.listFiles(new PyFilenameFilter(extention, onlyIfCanonicalPresent));
+ }
+
+ 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 {
+ StreamReader reader = new StreamReader(new UnicodeReader(input2));
+ StringBuilder buffer = new StringBuilder();
+ while (reader.peek() != '\0') {
+ buffer.append(reader.peek());
+ reader.forward();
+ }
+ CanonicalParser parser = new CanonicalParser(buffer.toString());
+ List<Event> result = new ArrayList<Event>();
+ while (parser.peekEvent() != null) {
+ result.add(parser.getEvent());
+ }
+ input2.close();
+ return result;
+ }
+
+ protected List<Event> parse(InputStream input) throws IOException {
+ StreamReader reader = new StreamReader(new UnicodeReader(input));
+ Parser parser = new ParserImpl(reader);
+ List<Event> result = new ArrayList<Event>();
+ while (parser.peekEvent() != null) {
+ result.add(parser.getEvent());
+ }
+ input.close();
+ 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 0000000..3f6f8f9
--- /dev/null
+++ b/src/test/java/org/pyyaml/PyMarkTest.java
@@ -0,0 +1,57 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.pyyaml;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * 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 0000000..3b25189
--- /dev/null
+++ b/src/test/java/org/pyyaml/PyReaderTest.java
@@ -0,0 +1,54 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.pyyaml;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.yaml.snakeyaml.error.YAMLException;
+import org.yaml.snakeyaml.reader.ReaderException;
+import org.yaml.snakeyaml.reader.StreamReader;
+import org.yaml.snakeyaml.reader.UnicodeReader;
+
+/**
+ * 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++) {
+ InputStream input = new FileInputStream(inputs[i]);
+ StreamReader stream = new StreamReader(new UnicodeReader(input));
+ try {
+ while (stream.peek() != '\u0000') {
+ stream.forward();
+ }
+ fail("Invalid stream must not be accepted: " + inputs[i].getAbsolutePath()
+ + "; encoding=" + stream.getEncoding());
+ } catch (ReaderException e) {
+ assertTrue(e.toString(),
+ e.toString().contains(" special characters are not allowed"));
+ } catch (YAMLException e) {
+ assertTrue(e.toString(), e.toString().contains("MalformedInputException"));
+ } finally {
+ input.close();
+ }
+ }
+ }
+}
diff --git a/src/test/java/org/pyyaml/PyRecursiveTest.java b/src/test/java/org/pyyaml/PyRecursiveTest.java
new file mode 100644
index 0000000..da353df
--- /dev/null
+++ b/src/test/java/org/pyyaml/PyRecursiveTest.java
@@ -0,0 +1,144 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+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 java.util.TreeMap;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.SafeConstructor;
+
+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();
+ String output1 = yaml.dump(value);
+ assertTrue(output1.contains("!!org.pyyaml.AnInstance"));
+ assertTrue(output1.contains("&id001"));
+ assertTrue(output1.contains("&id002"));
+ assertTrue(output1.contains("*id001"));
+ assertTrue(output1.contains("*id002"));
+ assertTrue(output1.contains("foo"));
+ assertTrue(output1.contains("bar"));
+ Map<AnInstance, AnInstance> value2 = (Map<AnInstance, AnInstance>) yaml.load(output1);
+ assertEquals(value.size(), value2.size());
+ for (AnInstance tmpInstance : value2.values()) {
+ assertSame(tmpInstance.getBar(), tmpInstance.getFoo());
+ assertSame(tmpInstance.getBar(), value2);
+ assertSame(tmpInstance, value2.get(tmpInstance));
+ }
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ public void testDictSafeConstructor() {
+ Map value = new TreeMap();
+ value.put("abc", "www");
+ value.put("qwerty", value);
+ Yaml yaml = new Yaml(new SafeConstructor());
+ String output1 = yaml.dump(value);
+ assertEquals("&id001\nabc: www\nqwerty: *id001\n", output1);
+ Map value2 = (Map) yaml.load(output1);
+ assertEquals(2, value2.size());
+ assertEquals("www", value2.get("abc"));
+ assertTrue(value2.get("qwerty") instanceof Map);
+ Map value3 = (Map) value2.get("qwerty");
+ assertTrue(value3.get("qwerty") instanceof Map);
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ public void testList() {
+ List value = new ArrayList();
+ value.add(value);
+ value.add("test");
+ value.add(new Integer(1));
+
+ Yaml yaml = new Yaml();
+ String output1 = yaml.dump(value);
+ assertEquals("&id001\n- *id001\n- test\n- 1\n", output1);
+ List value2 = (List) yaml.load(output1);
+ assertEquals(3, value2.size());
+ assertEquals(value.size(), value2.size());
+ assertSame(value2, value2.get(0));
+ // we expect self-reference as 1st element of the list
+ // let's remove self-reference and check other "simple" members of the
+ // list. otherwise assertEquals will lead us to StackOverflow
+ value.remove(0);
+ value2.remove(0);
+ assertEquals(value, value2);
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ public void testListSafeConstructor() {
+ List value = new ArrayList();
+ value.add(value);
+ value.add("test");
+ value.add(new Integer(1));
+
+ Yaml yaml = new Yaml(new SafeConstructor());
+ String output1 = yaml.dump(value);
+ assertEquals("&id001\n- *id001\n- test\n- 1\n", output1);
+ List value2 = (List) yaml.load(output1);
+ assertEquals(3, value2.size());
+ assertEquals(value.size(), value2.size());
+ assertSame(value2, value2.get(0));
+ // we expect self-reference as 1st element of the list
+ // let's remove self-reference and check other "simple" members of the
+ // list. otherwise assertEquals will lead us to StackOverflow
+ value.remove(0);
+ value2.remove(0);
+ assertEquals(value, value2);
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ public void testSet() {
+ Set value = new HashSet();
+ value.add(new AnInstance(value, value));
+ Yaml yaml = new Yaml();
+ String output1 = yaml.dump(value);
+ Set<AnInstance> value2 = (Set<AnInstance>) yaml.load(output1);
+
+ assertEquals(value.size(), value2.size());
+ for (AnInstance tmpInstance : value2) {
+ assertSame(tmpInstance.getBar(), tmpInstance.getFoo());
+ assertSame(tmpInstance.getBar(), value2);
+ }
+ }
+
+ public void testSet2() {
+ Set<Object> set = new HashSet<Object>(3);
+ set.add("aaa");
+ set.add(111);
+ set.add(set);
+ Yaml yaml = new Yaml();
+ try {
+ yaml.dump(set);
+ fail("Java does not allow a recursive set to be a key for a map.");
+ } catch (StackOverflowError e) {
+ // ignore
+ }
+ }
+}
diff --git a/src/test/java/org/pyyaml/PyStructureTest.java b/src/test/java/org/pyyaml/PyStructureTest.java
new file mode 100644
index 0000000..0d33464
--- /dev/null
+++ b/src/test/java/org/pyyaml/PyStructureTest.java
@@ -0,0 +1,302 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.pyyaml;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.composer.Composer;
+import org.yaml.snakeyaml.constructor.AbstractConstruct;
+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.NodeTuple;
+import org.yaml.snakeyaml.nodes.ScalarNode;
+import org.yaml.snakeyaml.nodes.SequenceNode;
+import org.yaml.snakeyaml.parser.ParserImpl;
+import org.yaml.snakeyaml.reader.StreamReader;
+import org.yaml.snakeyaml.reader.UnicodeReader;
+import org.yaml.snakeyaml.resolver.Resolver;
+
+/**
+ * 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;
+ if (scalar1.getImplicit().bothFalse() && scalar2.getImplicit().bothFalse()) {
+ assertEquals(scalar1.getTag(), scalar2.getTag());
+ }
+ assertEquals(scalar1.getValue(), scalar2.getValue());
+ }
+ }
+ }
+
+ public void testParser() {
+ 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 {
+ InputStream input = new FileInputStream(file);
+ List<Event> events1 = parse(input);
+ input.close();
+ 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());
+ 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() {
+ File[] canonicalFiles = getStreamsByExtension(".canonical", false);
+ assertTrue("No test files found.", canonicalFiles.length > 0);
+ for (File file : canonicalFiles) {
+ try {
+ InputStream input = new FileInputStream(file);
+ List<Event> events1 = parse(input);
+ input.close();
+ 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<NodeTuple> iter2 = seq2.getValue().iterator();
+ for (NodeTuple child1 : seq1.getValue()) {
+ NodeTuple child2 = iter2.next();
+ compareNodes(child1.getKeyNode(), child2.getKeyNode());
+ compareNodes(child1.getValueNode(), child2.getValueNode());
+ }
+ }
+ }
+ }
+
+ public void testComposer() {
+ File[] files = getStreamsByExtension(".data", true);
+ assertTrue("No test files found.", files.length > 0);
+ for (File file : files) {
+ try {
+ InputStream input = new FileInputStream(file);
+ List<Node> events1 = compose_all(input);
+ input.close();
+ int index = file.getAbsolutePath().lastIndexOf('.');
+ String canonicalName = file.getAbsolutePath().substring(0, index) + ".canonical";
+ File canonical = new File(canonicalName);
+ InputStream input2 = new FileInputStream(canonical);
+ List<Node> events2 = canonical_compose_all(input2);
+ input2.close();
+ 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 StreamReader(new UnicodeReader(file))),
+ new Resolver());
+ List<Node> documents = new ArrayList<Node>();
+ while (composer.checkNode()) {
+ documents.add(composer.getNode());
+ }
+ return documents;
+ }
+
+ private List<Node> canonical_compose_all(InputStream file) {
+ StreamReader reader = new StreamReader(new UnicodeReader(file));
+ StringBuilder buffer = new StringBuilder();
+ 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 ArrayList<Node>();
+ while (composer.checkNode()) {
+ documents.add(composer.getNode());
+ }
+ return documents;
+ }
+
+ class CanonicalLoader extends Yaml {
+ public CanonicalLoader() {
+ super(new MyConstructor());
+ }
+
+ @Override
+ public Iterable<Object> loadAll(Reader yaml) {
+ StreamReader reader = new StreamReader(yaml);
+ StringBuilder buffer = new StringBuilder();
+ 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 extends AbstractConstruct {
+ public Object construct(Node node) {
+ return constructScalar((ScalarNode) node);
+ }
+ }
+ }
+
+ public void testConstructor() {
+ File[] files = getStreamsByExtension(".data", true);
+ assertTrue("No test files found.", files.length > 0);
+ Yaml myYaml = new Yaml(new MyConstructor());
+ Yaml canonicalYaml = new CanonicalLoader();
+ for (File file : files) {
+ try {
+ InputStream input = new FileInputStream(file);
+ Iterable<Object> documents1 = myYaml.loadAll(input);
+ int index = file.getAbsolutePath().lastIndexOf('.');
+ String canonicalName = file.getAbsolutePath().substring(0, index) + ".canonical";
+ File canonical = new File(canonicalName);
+ InputStream input2 = new FileInputStream(canonical);
+ Iterable<Object> documents2 = canonicalYaml.loadAll(input2);
+ input2.close();
+ 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);
+ }
+ input.close();
+ } 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 0000000..646c4c2
--- /dev/null
+++ b/src/test/java/org/pyyaml/PyTokensTest.java
@@ -0,0 +1,148 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.pyyaml;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.yaml.snakeyaml.reader.StreamReader;
+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;
+
+/**
+ * imported from PyYAML
+ */
+public class PyTokensTest extends PyImportTest {
+
+ 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 ArrayList<String>();
+ for (int j = 0; j < split.length; j++) {
+ tokens2.add(split[j]);
+ }
+ //
+ List<String> tokens1 = new ArrayList<String>();
+ StreamReader reader = new StreamReader(new UnicodeReader(new FileInputStream(
+ getFileByName(dataName))));
+ Scanner scanner = new ScannerImpl(reader);
+ try {
+ while (scanner.checkToken(new Token.ID[0])) {
+ Token token = scanner.getToken();
+ if (!(token instanceof StreamStartToken || token instanceof StreamEndToken)) {
+ String replacement = replaces.get(token.getClass());
+ tokens1.add(replacement);
+ }
+ }
+ 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 IOException {
+ File[] files = getStreamsByExtension(".data", true);
+ assertTrue("No test files found.", files.length > 0);
+ for (File file : files) {
+ List<String> tokens = new ArrayList<String>();
+ InputStream input = new FileInputStream(file);
+ StreamReader reader = new StreamReader(new UnicodeReader(input));
+ Scanner scanner = new ScannerImpl(reader);
+ try {
+ while (scanner.checkToken(new Token.ID[0])) {
+ 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());
+ } finally {
+ input.close();
+ }
+ }
+ }
+}
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 0000000..0413a17
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/Address.java
@@ -0,0 +1,23 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+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 0000000..589e800
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/BinaryBean.java
@@ -0,0 +1,38 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+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 0000000..77815fb
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/BinaryJavaBeanTest.java
@@ -0,0 +1,35 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+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 0000000..6bc4d1c
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/Chapter2_1Test.java
@@ -0,0 +1,107 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml;
+
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+/**
+ * Test Chapter 2.1 from the YAML specification
+ *
+ * @see <a href="http://yaml.org/spec/1.1/"></a>
+ */
+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 0000000..88b7ec9
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/Chapter2_2Test.java
@@ -0,0 +1,112 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml;
+
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+/**
+ * Test Chapter 2.2 from the YAML specification
+ *
+ * @see <a href="http://yaml.org/spec/1.1/"></a>
+ */
+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());
+ }
+ }
+
+ public void testExample_2_12() {
+ YamlDocument document = new YamlDocument("example2_12.yaml");
+ @SuppressWarnings("unchecked")
+ List<Map<Object, Object>> list = (List<Map<Object, Object>>) document.getNativeData();
+ assertEquals(3, list.size());
+ Map<Object, Object> map1 = (Map<Object, Object>) list.get(0);
+ assertEquals(2, map1.size());
+ assertEquals("Super Hoop", map1.get("item"));
+ Map<Object, Object> map2 = (Map<Object, Object>) list.get(1);
+ assertEquals(2, map2.size());
+ assertEquals("Basketball", map2.get("item"));
+ Map<Object, Object> map3 = (Map<Object, Object>) 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 0000000..b4e671d
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/Chapter2_3Test.java
@@ -0,0 +1,134 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml;
+
+import java.io.InputStream;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.DumperOptions.ScalarStyle;
+
+/**
+ * Test Chapter 2.3 from the YAML specification
+ *
+ * @see <a href="http://yaml.org/spec/1.1/"></a>
+ */
+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");
+ DumperOptions options = new DumperOptions();
+ options.setDefaultScalarStyle(ScalarStyle.FOLDED);
+ Yaml yaml = new Yaml(options);
+ String data = (String) yaml.load(input);
+ assertEquals(etalon, data);
+ //
+ String dumped = yaml.dump(data);
+ String etalonDumped = Util.getLocalResource("specification/example2_15_dumped.yaml");
+ assertEquals(etalonDumped, dumped);
+ }
+
+ @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() {
+ 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() {
+ 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 0000000..3d36caa
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/Chapter2_4Test.java
@@ -0,0 +1,182 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml;
+
+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.AbstractConstruct;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.ScalarNode;
+import org.yaml.snakeyaml.nodes.Tag;
+
+/**
+ * Test Chapter 2.4 from the YAML specification
+ *
+ * @see <a href="http://yaml.org/spec/1.1/"></a>
+ */
+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() {
+ 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(new Tag("!something"), new ConstructSomething());
+ }
+
+ private class ConstructSomething extends AbstractConstruct {
+ 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() {
+ 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<String> list = new ArrayList<String>();
+ 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 0000000..bfe5551
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/Chapter2_5Test.java
@@ -0,0 +1,63 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+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
+ *
+ * @see <a href="http://yaml.org/spec/1.1/"></a>
+ */
+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/CollectionWithBeanYamlTest.java b/src/test/java/org/yaml/snakeyaml/CollectionWithBeanYamlTest.java
new file mode 100644
index 0000000..7b30d7b
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/CollectionWithBeanYamlTest.java
@@ -0,0 +1,85 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+import junit.framework.TestCase;
+
+public class CollectionWithBeanYamlTest extends TestCase {
+
+ @SuppressWarnings("unchecked")
+ public void testYamlMap() {
+ Map<String, Bean> data = new TreeMap<String, Bean>();
+ data.put("gold1", new Bean());
+ data.put("gold2", new Bean());
+
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(data);
+ assertEquals(
+ "gold1: !!org.yaml.snakeyaml.CollectionWithBeanYamlTest$Bean {a: ''}\ngold2: !!org.yaml.snakeyaml.CollectionWithBeanYamlTest$Bean {a: ''}\n",
+ output);
+ Object o = yaml.load(output);
+
+ assertTrue(o instanceof Map);
+ Map<String, Bean> m = (Map<String, Bean>) o;
+ assertTrue(m.get("gold1") instanceof Bean);
+ assertTrue("" + m.get("gold2").getClass(), m.get("gold2") instanceof Bean);
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testYamlList() {
+ List<Bean> data = new ArrayList<Bean>();
+ data.add(new Bean("1"));
+ data.add(new Bean("2"));
+
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(data);
+ assertEquals(
+ "- !!org.yaml.snakeyaml.CollectionWithBeanYamlTest$Bean {a: '1'}\n- !!org.yaml.snakeyaml.CollectionWithBeanYamlTest$Bean {a: '2'}\n",
+ output);
+ Object o = yaml.load(output);
+
+ assertTrue(o instanceof List);
+ List<Bean> m = (List<Bean>) o;
+ assertEquals(2, m.size());
+ assertTrue(m.get(0) instanceof Bean);
+ assertTrue(m.get(1) instanceof Bean);
+ }
+
+ public static class Bean {
+ private String a;
+
+ public Bean() {
+ a = "";
+ }
+
+ public Bean(String value) {
+ a = value;
+ }
+
+ public String getA() {
+ return a;
+ }
+
+ public void setA(String s) {
+ a = s;
+ }
+ }
+}
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 0000000..f36fb7b
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/DumperOptionsTest.java
@@ -0,0 +1,473 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.emitter.Emitter;
+import org.yaml.snakeyaml.error.YAMLException;
+import org.yaml.snakeyaml.nodes.Tag;
+import org.yaml.snakeyaml.representer.Representer;
+
+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.setDefaultScalarStyle(DumperOptions.ScalarStyle.DOUBLE_QUOTED);
+ yaml = new Yaml(options);
+ assertEquals("\"123\"\n", yaml.dump("123"));
+ //
+ options.setDefaultScalarStyle(DumperOptions.ScalarStyle.SINGLE_QUOTED);
+ yaml = new Yaml(options);
+ assertEquals("'123'\n", yaml.dump("123"));
+ //
+ options.setDefaultScalarStyle(DumperOptions.ScalarStyle.PLAIN);
+ yaml = new Yaml(options);
+ assertEquals("'123'\n", yaml.dump("123"));
+ assertEquals("abc\n", yaml.dump("abc"));
+ // null check
+ try {
+ options.setDefaultScalarStyle(null);
+ fail("Null must not be accepted.");
+ } catch (NullPointerException e) {
+ assertEquals("Use ScalarStyle enum.", e.getMessage());
+ }
+ }
+
+ public void testDefaultFlowStyle() {
+ Yaml yaml = new Yaml();
+ List<Integer> list = new ArrayList<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.FlowStyle.FLOW);
+ yaml = new Yaml(options);
+ assertEquals("[1, 2, 3]\n", yaml.dump(list));
+ //
+ options = new DumperOptions();
+ options.setDefaultFlowStyle(DumperOptions.FlowStyle.FLOW);
+ options.setPrettyFlow(true);
+ yaml = new Yaml(options);
+ assertEquals("[\n 1,\n 2,\n 3]\n", yaml.dump(list));
+ //
+ options = new DumperOptions();
+ options.setDefaultFlowStyle(DumperOptions.FlowStyle.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 FlowStyle enum.", e.getMessage());
+ }
+ }
+
+ public void testDefaultFlowStyleNested() {
+ Yaml yaml = new Yaml();
+ List<Integer> list = new ArrayList<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);
+ String result = yaml.dump(map);
+ assertEquals("a: b\nc: [1, 2, 3]\n", result);
+ //
+ DumperOptions options = new DumperOptions();
+ options = new DumperOptions();
+ options.setDefaultFlowStyle(DumperOptions.FlowStyle.FLOW);
+ yaml = new Yaml(options);
+ assertEquals("{a: b, c: [1, 2, 3]}\n", yaml.dump(map));
+ //
+ options = new DumperOptions();
+ options.setDefaultFlowStyle(DumperOptions.FlowStyle.FLOW);
+ options.setPrettyFlow(true);
+ yaml = new Yaml(options);
+ result = yaml.dump(map);
+ assertEquals("{\n a: b,\n c: [\n 1,\n 2,\n 3]\n \n}\n", result);
+ //
+ options = new DumperOptions();
+ options.setDefaultFlowStyle(DumperOptions.FlowStyle.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 ArrayList<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 ArrayList<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 testLineBreakForPlatform() {
+ DumperOptions.LineBreak lineBreak = DumperOptions.LineBreak.getPlatformLineBreak();
+ assertEquals("Line break must match platform's default.",
+ System.getProperty("line.separator"), lineBreak.getString());
+ //
+ Yaml yaml = new Yaml();
+ List<Integer> list = new ArrayList<Integer>();
+ list.add(1);
+ list.add(2);
+ DumperOptions options = new DumperOptions();
+ options.setLineBreak(DumperOptions.LineBreak.getPlatformLineBreak());
+ yaml = new Yaml(options);
+ assertEquals("[1, 2]", yaml.dump(list).trim());
+ }
+
+ public void testLineBreakForPlatformUnix() {
+ System.setProperty("line.separator", "\n");
+ assertEquals("\n", System.getProperty("line.separator"));
+ DumperOptions.LineBreak lineBreak = DumperOptions.LineBreak.getPlatformLineBreak();
+ assertEquals("Line break must match platform's default.",
+ System.getProperty("line.separator"), lineBreak.getString());
+ assertEquals("Unknown Line break must match UNIX line break.", "\n", lineBreak.getString());
+ }
+
+ public void testLineBreakForPlatformMac() {
+ System.setProperty("line.separator", "\r");
+ assertEquals("\r", System.getProperty("line.separator"));
+ DumperOptions.LineBreak lineBreak = DumperOptions.LineBreak.getPlatformLineBreak();
+ assertEquals("Line break must match platform's default.",
+ System.getProperty("line.separator"), lineBreak.getString());
+ assertEquals("Unknown Line break must match UNIX line break.", "\r", lineBreak.getString());
+ }
+
+ public void testLineBreakForPlatformWin() {
+ System.setProperty("line.separator", "\r\n");
+ assertEquals("\r\n", System.getProperty("line.separator"));
+ DumperOptions.LineBreak lineBreak = DumperOptions.LineBreak.getPlatformLineBreak();
+ assertEquals("Line break must match platform's default.",
+ System.getProperty("line.separator"), lineBreak.getString());
+ assertEquals("Unknown Line break must match UNIX line break.", "\r\n",
+ lineBreak.getString());
+ }
+
+ public void testLineBreakForPlatformUnknown() {
+ System.setProperty("line.separator", "\n\r");
+ assertEquals("\n\r", System.getProperty("line.separator"));
+ DumperOptions.LineBreak lineBreak = DumperOptions.LineBreak.getPlatformLineBreak();
+ assertEquals("Unknown Line break must match UNIX line break.", "\n", lineBreak.getString());
+ }
+
+ public void testExplicitStart() {
+ Yaml yaml = new Yaml();
+ List<Integer> list = new ArrayList<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 ArrayList<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));
+ //
+ assertEquals("Version: 1.1", DumperOptions.Version.V1_1.toString());
+ }
+
+ public void testTags() {
+ Yaml yaml = new Yaml();
+ List<Integer> list = new ArrayList<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.PREFIX);
+ 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 testToString() {
+ DumperOptions.ScalarStyle scalarStyle = DumperOptions.ScalarStyle.LITERAL;
+ assertEquals("Scalar style: '|'", scalarStyle.toString());
+ //
+ DumperOptions.FlowStyle flowStyle = DumperOptions.FlowStyle.BLOCK;
+ assertEquals("Flow style: 'false'", flowStyle.toString());
+ //
+ DumperOptions.LineBreak lb = DumperOptions.LineBreak.UNIX;
+ assertEquals("Line break: UNIX", lb.toString());
+ }
+
+ public void testWithRepresenter() {
+ Representer representer = new Representer();
+ DumperOptions options = new DumperOptions();
+ options.setIndent(4);
+ options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
+ Yaml yaml = new Yaml(representer, options);
+ List<Integer> list = new ArrayList<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:\n- 1\n- 2\n- 3\n", yaml.dump(map));
+ }
+
+ public void testSplitLinesDoubleQuoted() {
+ DumperOptions options = new DumperOptions();
+ options.setDefaultScalarStyle(DumperOptions.ScalarStyle.DOUBLE_QUOTED);
+ Yaml yaml;
+ String output;
+
+ // Split lines enabled (default)
+ assertTrue(options.getSplitLines());
+ yaml = new Yaml(options);
+ output = yaml.dump("1111111111 2222222222 3333333333 4444444444 5555555555 6666666666 7777777777 8888888888 9999999999 0000000000");
+ assertEquals("\"1111111111 2222222222 3333333333 4444444444 5555555555 6666666666 7777777777 8888888888\\\n \\ 9999999999 0000000000\"\n", output);
+
+ // Split lines disabled
+ options.setSplitLines(false);
+ assertFalse(options.getSplitLines());
+ yaml = new Yaml(options);
+ output = yaml.dump("1111111111 2222222222 3333333333 4444444444 5555555555 6666666666 7777777777 8888888888 9999999999 0000000000");
+ assertEquals("\"1111111111 2222222222 3333333333 4444444444 5555555555 6666666666 7777777777 8888888888 9999999999 0000000000\"\n", output);
+ }
+
+ public void testSplitLinesSingleQuoted() {
+ DumperOptions options = new DumperOptions();
+ options.setDefaultScalarStyle(DumperOptions.ScalarStyle.SINGLE_QUOTED);
+ Yaml yaml;
+ String output;
+
+ // Split lines enabled (default)
+ assertTrue(options.getSplitLines());
+ yaml = new Yaml(options);
+ output = yaml.dump("1111111111 2222222222 3333333333 4444444444 5555555555 6666666666 7777777777 8888888888 9999999999 0000000000");
+ assertEquals("'1111111111 2222222222 3333333333 4444444444 5555555555 6666666666 7777777777 8888888888\n 9999999999 0000000000'\n", output);
+
+ // Split lines disabled
+ options.setSplitLines(false);
+ assertFalse(options.getSplitLines());
+ yaml = new Yaml(options);
+ output = yaml.dump("1111111111 2222222222 3333333333 4444444444 5555555555 6666666666 7777777777 8888888888 9999999999 0000000000");
+ assertEquals("'1111111111 2222222222 3333333333 4444444444 5555555555 6666666666 7777777777 8888888888 9999999999 0000000000'\n", output);
+ }
+
+ public void testSplitLinesFolded() {
+ DumperOptions options = new DumperOptions();
+ options.setDefaultScalarStyle(DumperOptions.ScalarStyle.FOLDED);
+ Yaml yaml;
+ String output;
+
+ // Split lines enabled (default)
+ assertTrue(options.getSplitLines());
+ yaml = new Yaml(options);
+ output = yaml.dump("1111111111 2222222222 3333333333 4444444444 5555555555 6666666666 7777777777 8888888888 9999999999 0000000000");
+ assertEquals(">-\n 1111111111 2222222222 3333333333 4444444444 5555555555 6666666666 7777777777 8888888888\n 9999999999 0000000000\n", output);
+
+ // Split lines disabled
+ options.setSplitLines(false);
+ assertFalse(options.getSplitLines());
+ yaml = new Yaml(options);
+ output = yaml.dump("1111111111 2222222222 3333333333 4444444444 5555555555 6666666666 7777777777 8888888888 9999999999 0000000000");
+ assertEquals(">-\n 1111111111 2222222222 3333333333 4444444444 5555555555 6666666666 7777777777 8888888888 9999999999 0000000000\n", output);
+ }
+
+ public void testSplitLinesLiteral() {
+ DumperOptions options = new DumperOptions();
+ options.setDefaultScalarStyle(DumperOptions.ScalarStyle.LITERAL);
+ Yaml yaml;
+ String output;
+
+ // Split lines enabled (default) -- split lines does not apply to literal style
+ assertTrue(options.getSplitLines());
+ yaml = new Yaml(options);
+ output = yaml.dump("1111111111 2222222222 3333333333 4444444444 5555555555 6666666666 7777777777 8888888888 9999999999 0000000000");
+ assertEquals("|-\n 1111111111 2222222222 3333333333 4444444444 5555555555 6666666666 7777777777 8888888888 9999999999 0000000000\n", output);
+ }
+
+ public void testSplitLinesPlain() {
+ DumperOptions options = new DumperOptions();
+ options.setDefaultScalarStyle(DumperOptions.ScalarStyle.PLAIN);
+ Yaml yaml;
+ String output;
+
+ // Split lines enabled (default) -- split lines does not apply to plain style
+ assertTrue(options.getSplitLines());
+ yaml = new Yaml(options);
+ output = yaml.dump("1111111111 2222222222 3333333333 4444444444 5555555555 6666666666 7777777777 8888888888 9999999999 0000000000");
+ assertEquals("1111111111 2222222222 3333333333 4444444444 5555555555 6666666666 7777777777 8888888888 9999999999 0000000000\n", output);
+ }
+
+ public void testSetIndicatorIndentNegative() {
+ DumperOptions options = new DumperOptions();
+ try {
+ options.setIndicatorIndent(-1);
+ fail("Negative indent must not be accepted.");
+ } catch (YAMLException e) {
+ assertEquals("Indicator indent must be non-negative.", e.getMessage());
+ }
+ }
+
+ public void testSetIndicatorIndentTooBig() {
+ DumperOptions options = new DumperOptions();
+ try {
+ options.setIndicatorIndent(100);
+ fail("Negative indent must not be accepted.");
+ } catch (YAMLException e) {
+ assertEquals("Indicator indent must be at most Emitter.MAX_INDENT-1: 9", e.getMessage());
+ }
+ }
+
+ public void testCreateUnknownStyle() {
+ try {
+ DumperOptions.ScalarStyle.createStyle(' ');
+ fail("Negative indent must not be accepted.");
+ } catch (YAMLException e) {
+ assertEquals("Unknown scalar style character: ", e.getMessage());
+ }
+ }
+
+ public void testCreateStyle() {
+ assertEquals(DumperOptions.ScalarStyle.DOUBLE_QUOTED, DumperOptions.ScalarStyle.createStyle('"'));
+ assertEquals(DumperOptions.ScalarStyle.SINGLE_QUOTED, DumperOptions.ScalarStyle.createStyle('\''));
+ assertEquals(DumperOptions.ScalarStyle.LITERAL, DumperOptions.ScalarStyle.createStyle('|'));
+ assertEquals(DumperOptions.ScalarStyle.FOLDED, DumperOptions.ScalarStyle.createStyle('>'));
+ assertEquals(DumperOptions.ScalarStyle.PLAIN, DumperOptions.ScalarStyle.createStyle(null));
+ }
+}
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 0000000..6365371
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/EnumBean.java
@@ -0,0 +1,48 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+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 0000000..3587fac
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/EnumTest.java
@@ -0,0 +1,199 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+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 testDumpOverriddenToString() {
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(DumperOptions.FlowStyle.BLOCK);
+ assertEquals("!!org.yaml.snakeyaml.DumperOptions$FlowStyle 'BLOCK'\n", output);
+ }
+
+ public void testDumpEnumArray() {
+ DumperOptions options = new DumperOptions();
+ options.setDefaultFlowStyle(DumperOptions.FlowStyle.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.FlowStyle.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.FlowStyle.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.FlowStyle.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.FlowStyle.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.FlowStyle.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 CLUBS: 1\n 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);
+ }
+
+ public void testLoadOverridenToString() {
+ Yaml yaml = new Yaml();
+ assertEquals(DumperOptions.FlowStyle.BLOCK,
+ yaml.load("!!org.yaml.snakeyaml.DumperOptions$FlowStyle 'BLOCK'\n"));
+ }
+
+ @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(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 0000000..aa54464
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/Example2_24Test.java
@@ -0,0 +1,247 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml;
+
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.constructor.AbstractConstruct;
+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.nodes.Tag;
+import org.yaml.snakeyaml.representer.Represent;
+import org.yaml.snakeyaml.representer.Representer;
+
+/**
+ * Test Example 2.24 from the YAML specification
+ *
+ * @see <a href="http://yaml.org/spec/1.1/"></a>
+ */
+public class Example2_24Test extends TestCase {
+ class MyConstructor extends Constructor {
+ public MyConstructor() {
+ this.yamlConstructors.put(new Tag("tag:clarkevans.com,2002:shape"),
+ new ConstructShape());
+ this.yamlConstructors.put(new Tag("tag:clarkevans.com,2002:circle"),
+ new ConstructCircle());
+ this.yamlConstructors.put(new Tag("tag:clarkevans.com,2002:line"), new ConstructLine());
+ this.yamlConstructors.put(new Tag("tag:clarkevans.com,2002:label"),
+ new ConstructLabel());
+ }
+
+ private class ConstructShape extends AbstractConstruct {
+ @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 extends AbstractConstruct {
+ @SuppressWarnings("unchecked")
+ public Object construct(Node node) {
+ MappingNode mnode = (MappingNode) node;
+ Map<Object, Object> values = constructMapping(mnode);
+ Circle circle = new Circle((Map<String, Integer>) values.get("center"),
+ (Integer) values.get("radius"));
+ return circle;
+ }
+ }
+
+ private class ConstructLine extends AbstractConstruct {
+ @SuppressWarnings("unchecked")
+ public Object construct(Node node) {
+ MappingNode mnode = (MappingNode) node;
+ Map<Object, Object> values = constructMapping(mnode);
+ Line line = new Line((Map<String, Integer>) values.get("start"),
+ (Map<String, Integer>) values.get("finish"));
+ return line;
+ }
+ }
+
+ private class ConstructLabel extends AbstractConstruct {
+ @SuppressWarnings("unchecked")
+ public Object construct(Node node) {
+ MappingNode mnode = (MappingNode) node;
+ Map<Object, Object> values = constructMapping(mnode);
+ Label label = new Label((Map<String, Integer>) 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(new Tag("!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(new Tag("!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(new Tag("!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(new Tag("!label"), map, Boolean.FALSE);
+ }
+ }
+
+ private class RepresentHex implements Represent {
+ public Node representData(Object data) {
+ HexInteger hex = (HexInteger) data;
+ return representScalar(Tag.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() {
+ Yaml yaml = new Yaml(new MyConstructor());
+ Shape shape = (Shape) yaml.load(Util.getLocalResource("specification/example2_24.yaml"));
+ assertNotNull(shape);
+ yaml = new Yaml(new MyRepresenter());
+ 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 0000000..e51be0f
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/Example2_27Test.java
@@ -0,0 +1,41 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.constructor.Constructor;
+
+/**
+ * Test Example 2.27 from the YAML specification
+ *
+ * @see <a href="http://yaml.org/spec/1.1/"></a>
+ */
+public class Example2_27Test extends TestCase {
+
+ public void testExample_2_27() {
+ Yaml yaml = new Yaml(new Constructor(Invoice.class));
+ Invoice invoice = (Invoice) yaml.load(Util
+ .getLocalResource("specification/example2_27.yaml"));
+ assertNotNull(invoice);
+ Person billTo = invoice.billTo;
+ assertEquals("Dumars", billTo.family);
+ yaml = new Yaml();
+ String output = yaml.dump(invoice);
+ String etalon = Util.getLocalResource("specification/example2_27_dumped.yaml");
+ assertEquals(etalon, output);
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/InputOutputExceptionTest.java b/src/test/java/org/yaml/snakeyaml/InputOutputExceptionTest.java
new file mode 100644
index 0000000..d309b54
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/InputOutputExceptionTest.java
@@ -0,0 +1,80 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Writer;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.error.YAMLException;
+
+public class InputOutputExceptionTest extends TestCase {
+ public void testIOExceptionOnLoad() {
+ try {
+ new Yaml().load(new BrokenInputStream());
+ fail("Input must be broken.");
+ } catch (YAMLException e) {
+ assertTrue(e.getCause() instanceof IOException);
+ assertEquals("java.io.IOException: Broken 2", e.getMessage());
+ }
+ }
+
+ public void testIOExceptionOnDump() {
+ try {
+ new Yaml().dump("something", new BrokenWriter());
+ fail("Output must be broken.");
+ } catch (YAMLException e) {
+ assertTrue(e.getCause() instanceof IOException);
+ assertEquals("java.io.IOException: Broken 12", e.getMessage());
+ }
+ }
+
+ private static class BrokenInputStream extends InputStream {
+ @Override
+ public int read() throws IOException {
+ throw new IOException("Broken 1");
+ }
+
+ @Override
+ public int read(byte[] bytes, int i, int i1) throws IOException {
+ throw new IOException("Broken 2");
+ }
+
+ @Override
+ public void close() throws IOException {
+ throw new IOException("Broken 3");
+ }
+ }
+
+ private static class BrokenWriter extends Writer {
+ @Override
+ public void close() throws IOException {
+ throw new IOException("Broken 10");
+ }
+
+ @Override
+ public void flush() throws IOException {
+ throw new IOException("Broken 11");
+ }
+
+ @Override
+ public void write(char[] cbuf, int off, int len) throws IOException {
+ throw new IOException("Broken 12");
+ }
+ }
+}
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 0000000..0e80775
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/Invoice.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+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/JavaBeanTimeStampTest.java b/src/test/java/org/yaml/snakeyaml/JavaBeanTimeStampTest.java
new file mode 100644
index 0000000..90a456c
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/JavaBeanTimeStampTest.java
@@ -0,0 +1,61 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml;
+
+import java.sql.Date;
+import java.sql.Timestamp;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.DumperOptions.FlowStyle;
+
+public class JavaBeanTimeStampTest extends TestCase {
+ public void testLoadDefaultJavaSqlTimestamp() {
+ JavaBeanWithSqlTimestamp javaBeanToDump = new JavaBeanWithSqlTimestamp();
+ Timestamp stamp = new Timestamp(1000000000000L);
+ javaBeanToDump.setTimestamp(stamp);
+ Date date = new Date(1001376000000L);
+ javaBeanToDump.setDate(date);
+ DumperOptions options = new DumperOptions();
+ options.setDefaultFlowStyle(FlowStyle.BLOCK);
+ Yaml yaml = new Yaml(options);
+ String dumpStr = yaml.dump(javaBeanToDump);
+ assertEquals(
+ "!!org.yaml.snakeyaml.JavaBeanWithSqlTimestamp\ndate: 2001-09-25T00:00:00Z\ntimestamp: 2001-09-09T01:46:40Z\n",
+ dumpStr);
+ Yaml loader = new Yaml();
+ JavaBeanWithSqlTimestamp javaBeanToLoad = loader.loadAs(dumpStr,
+ JavaBeanWithSqlTimestamp.class);
+ assertEquals(stamp, javaBeanToLoad.getTimestamp());
+ assertEquals(date, javaBeanToLoad.getDate());
+ }
+
+ public void testLoadDefaultJavaSqlTimestampNoGlobalTag() {
+ JavaBeanWithSqlTimestamp javaBeanToDump = new JavaBeanWithSqlTimestamp();
+ Timestamp stamp = new Timestamp(1000000000000L);
+ javaBeanToDump.setTimestamp(stamp);
+ Date date = new Date(1001376000000L);
+ javaBeanToDump.setDate(date);
+ Yaml yaml = new Yaml();
+ String dumpStr = yaml.dumpAsMap(javaBeanToDump);
+ assertEquals("date: 2001-09-25T00:00:00Z\ntimestamp: 2001-09-09T01:46:40Z\n", dumpStr);
+ Yaml loader = new Yaml();
+ JavaBeanWithSqlTimestamp javaBeanToLoad = loader.loadAs(dumpStr,
+ JavaBeanWithSqlTimestamp.class);
+ assertEquals(stamp, javaBeanToLoad.getTimestamp());
+ assertEquals(date, javaBeanToLoad.getDate());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/JavaBeanWithNullValues.java b/src/test/java/org/yaml/snakeyaml/JavaBeanWithNullValues.java
new file mode 100644
index 0000000..83b8d81
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/JavaBeanWithNullValues.java
@@ -0,0 +1,106 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml;
+
+import java.sql.Timestamp;
+import java.util.Date;
+
+public class JavaBeanWithNullValues {
+ private String string;
+ private Integer integer;
+ private Float float1;
+ private Double double1;
+ private Long long1;
+ private Date date;
+ private java.sql.Date sqlDate;
+ private Timestamp timestamp;
+ private Boolean boolean1;
+
+ public JavaBeanWithNullValues() {
+ }
+
+ public String getString() {
+ return string;
+ }
+
+ public void setString(String string) {
+ this.string = string;
+ }
+
+ public Integer getInteger() {
+ return integer;
+ }
+
+ public void setInteger(Integer integer) {
+ this.integer = integer;
+ }
+
+ public Float getFloat1() {
+ return float1;
+ }
+
+ public void setFloat1(Float float1) {
+ this.float1 = float1;
+ }
+
+ public Double getDouble1() {
+ return double1;
+ }
+
+ public void setDouble1(Double double1) {
+ this.double1 = double1;
+ }
+
+ public Long getLong1() {
+ return long1;
+ }
+
+ public void setLong1(Long long1) {
+ this.long1 = long1;
+ }
+
+ public Date getDate() {
+ return date;
+ }
+
+ public void setDate(Date date) {
+ this.date = date;
+ }
+
+ public java.sql.Date getSqlDate() {
+ return sqlDate;
+ }
+
+ public void setSqlDate(java.sql.Date sqlDate) {
+ this.sqlDate = sqlDate;
+ }
+
+ public Timestamp getTimestamp() {
+ return timestamp;
+ }
+
+ public void setTimestamp(Timestamp timestamp) {
+ this.timestamp = timestamp;
+ }
+
+ public Boolean getBoolean1() {
+ return boolean1;
+ }
+
+ public void setBoolean1(Boolean boolean1) {
+ this.boolean1 = boolean1;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/JavaBeanWithNullValuesTest.java b/src/test/java/org/yaml/snakeyaml/JavaBeanWithNullValuesTest.java
new file mode 100644
index 0000000..dc63f48
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/JavaBeanWithNullValuesTest.java
@@ -0,0 +1,187 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml;
+
+import java.sql.Timestamp;
+import java.util.Date;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.Tag;
+import org.yaml.snakeyaml.representer.Represent;
+import org.yaml.snakeyaml.representer.Representer;
+
+public class JavaBeanWithNullValuesTest extends TestCase {
+ private Yaml loader;
+
+ @Override
+ protected void setUp() {
+ loader = new Yaml();
+ }
+
+ public void testNotNull() {
+ String dumpStr = dumpJavaBeanWithNullValues(false);
+ // System.out.println(dumpStr);
+ Yaml yaml = new Yaml();
+ JavaBeanWithNullValues parsed = (JavaBeanWithNullValues) yaml.load(dumpStr);
+ assertNotNull(parsed.getString());
+ assertNotNull(parsed.getBoolean1());
+ assertNotNull(parsed.getDate());
+ assertNotNull(parsed.getDouble1());
+ assertNotNull(parsed.getFloat1());
+ assertNotNull(parsed.getInteger());
+ assertNotNull(parsed.getLong1());
+ assertNotNull(parsed.getSqlDate());
+ assertNotNull(parsed.getTimestamp());
+ //
+ parsed = loader.loadAs(dumpStr, JavaBeanWithNullValues.class);
+ assertNotNull(parsed.getString());
+ assertNotNull(parsed.getBoolean1());
+ assertNotNull(parsed.getDate());
+ assertNotNull(parsed.getDouble1());
+ assertNotNull(parsed.getFloat1());
+ assertNotNull(parsed.getInteger());
+ assertNotNull(parsed.getLong1());
+ assertNotNull(parsed.getSqlDate());
+ assertNotNull(parsed.getTimestamp());
+ }
+
+ public void testNull() {
+ String dumpStr = dumpJavaBeanWithNullValues(true);
+ Yaml yaml = new Yaml();
+ JavaBeanWithNullValues parsed = (JavaBeanWithNullValues) yaml.load(dumpStr);
+ assertNull(parsed.getString());
+ //
+ parsed = loader.loadAs(dumpStr, JavaBeanWithNullValues.class);
+ assertNull(parsed.getString());
+ }
+
+ public void testNullStringAndBoolean() {
+ JavaBeanWithNullValues javaBeanWithNullValues = new JavaBeanWithNullValues();
+ DumperOptions options = new DumperOptions();
+ options.setDefaultScalarStyle(DumperOptions.ScalarStyle.DOUBLE_QUOTED);
+ options.setExplicitStart(true);
+ options.setExplicitEnd(true);
+ Yaml yaml = new Yaml(new CustomRepresenter(), options);
+ javaBeanWithNullValues.setBoolean1(null);
+ javaBeanWithNullValues.setDate(new Date(System.currentTimeMillis()));
+ javaBeanWithNullValues.setDouble1(1d);
+ javaBeanWithNullValues.setFloat1(1f);
+ javaBeanWithNullValues.setInteger(1);
+ javaBeanWithNullValues.setLong1(1l);
+ javaBeanWithNullValues.setSqlDate(new java.sql.Date(System.currentTimeMillis()));
+ javaBeanWithNullValues.setString(null); // ok
+ javaBeanWithNullValues.setTimestamp(new Timestamp(System.currentTimeMillis()));
+
+ String dumpStr = yaml.dump(javaBeanWithNullValues);
+ // System.out.println(dumpStr);
+ yaml = new Yaml();
+ JavaBeanWithNullValues parsed = (JavaBeanWithNullValues) yaml.load(dumpStr);
+ assertNull(" expect null, got " + parsed.getBoolean1(), parsed.getBoolean1());
+ assertNull(" expect null, got " + parsed.getString(), parsed.getString());
+ }
+
+ public void testNoRootTag() {
+ JavaBeanWithNullValues javaBeanWithNullValues = new JavaBeanWithNullValues();
+ DumperOptions options = new DumperOptions();
+ options.setDefaultScalarStyle(DumperOptions.ScalarStyle.DOUBLE_QUOTED);
+ options.setExplicitStart(true);
+ options.setExplicitEnd(true);
+ Yaml yaml = new Yaml(new CustomRepresenter(), options);
+ javaBeanWithNullValues.setBoolean1(null);
+ javaBeanWithNullValues.setDate(new Date(System.currentTimeMillis()));
+ javaBeanWithNullValues.setDouble1(1d);
+ javaBeanWithNullValues.setFloat1(1f);
+ javaBeanWithNullValues.setInteger(1);
+ javaBeanWithNullValues.setLong1(1l);
+ javaBeanWithNullValues.setSqlDate(new java.sql.Date(System.currentTimeMillis()));
+ javaBeanWithNullValues.setString(null); // ok
+ javaBeanWithNullValues.setTimestamp(new Timestamp(System.currentTimeMillis()));
+
+ String dumpStr = yaml.dumpAsMap(javaBeanWithNullValues);
+ // System.out.println(dumpStr);
+ assertFalse("No explicit root tag must be used.",
+ dumpStr.contains("JavaBeanWithNullValues"));
+ yaml = new Yaml(new CustomRepresenter(), options);
+ JavaBeanWithNullValues parsed = loader.loadAs(dumpStr, JavaBeanWithNullValues.class);
+ assertNull(" expect null, got " + parsed.getBoolean1(), parsed.getBoolean1());
+ assertNull(" expect null, got " + parsed.getString(), parsed.getString());
+ assertEquals(1d, parsed.getDouble1());
+ assertEquals(1f, parsed.getFloat1());
+ assertEquals(new Integer(1), parsed.getInteger());
+ assertEquals(new Long(1l), parsed.getLong1());
+ }
+
+ private String dumpJavaBeanWithNullValues(boolean nullValues) {
+ JavaBeanWithNullValues javaBeanWithNullValues = new JavaBeanWithNullValues();
+ DumperOptions options = new DumperOptions();
+ options.setDefaultScalarStyle(DumperOptions.ScalarStyle.DOUBLE_QUOTED);
+ options.setExplicitStart(true);
+ options.setExplicitEnd(true);
+ Yaml yaml = new Yaml(new CustomRepresenter(), options);
+ if (nullValues) {
+ return yaml.dump(javaBeanWithNullValues);
+ }
+ javaBeanWithNullValues.setBoolean1(false);
+ javaBeanWithNullValues.setDate(new Date(System.currentTimeMillis()));
+ javaBeanWithNullValues.setDouble1(1d);
+ javaBeanWithNullValues.setFloat1(1f);
+ javaBeanWithNullValues.setInteger(1);
+ javaBeanWithNullValues.setLong1(1l);
+ javaBeanWithNullValues.setSqlDate(new java.sql.Date(System.currentTimeMillis()));
+ javaBeanWithNullValues.setString(""); // ok
+ javaBeanWithNullValues.setTimestamp(new Timestamp(System.currentTimeMillis()));
+ return yaml.dump(javaBeanWithNullValues);
+ }
+
+ public class CustomRepresenter extends Representer {
+ public CustomRepresenter() {
+ this.representers.put(Float.class, new RepresentFloat());
+ this.representers.put(Long.class, new RepresentLong());
+ this.representers.put(java.sql.Date.class, new RepresentDate());
+ this.representers.put(java.sql.Timestamp.class, new RepresentTime());
+ }
+
+ private class RepresentFloat implements Represent {
+ public Node representData(Object data) {
+ return representScalar(new Tag(Tag.PREFIX + "java.lang.Float"),
+ ((Float) data).toString());
+ }
+ }
+
+ private class RepresentLong implements Represent {
+ public Node representData(Object data) {
+ return representScalar(new Tag(Tag.PREFIX + "java.lang.Long"),
+ ((Long) data).toString());
+ }
+ }
+
+ private class RepresentDate implements Represent {
+ public Node representData(Object data) {
+ return representScalar(new Tag(Tag.PREFIX + "java.sql.Date"),
+ ((java.sql.Date) data).toString());
+ }
+ }
+
+ private class RepresentTime implements Represent {
+ public Node representData(Object data) {
+ return representScalar(new Tag(Tag.PREFIX + "java.sql.Timestamp"),
+ ((java.sql.Timestamp) data).toString());
+ }
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/JavaBeanWithSqlTimestamp.java b/src/test/java/org/yaml/snakeyaml/JavaBeanWithSqlTimestamp.java
new file mode 100644
index 0000000..ae31768
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/JavaBeanWithSqlTimestamp.java
@@ -0,0 +1,37 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml;
+
+public class JavaBeanWithSqlTimestamp {
+ private java.sql.Timestamp timestamp;
+ private java.sql.Date date;
+
+ public java.sql.Timestamp getTimestamp() {
+ return timestamp;
+ }
+
+ public void setTimestamp(java.sql.Timestamp timestamp) {
+ this.timestamp = timestamp;
+ }
+
+ public java.sql.Date getDate() {
+ return date;
+ }
+
+ public void setDate(java.sql.Date date) {
+ this.date = date;
+ }
+}
\ No newline at end of file
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 0000000..088130f
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/Person.java
@@ -0,0 +1,22 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+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 0000000..badb80d
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/Product.java
@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml;
+
+public class Product {
+ public String sku;
+ public Integer quantity;
+ public String description;
+ public Float price;
+
+ @Override
+ public String toString() {
+ return "Product: " + sku;
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/org/yaml/snakeyaml/PropertyUtilsSharingTest.java b/src/test/java/org/yaml/snakeyaml/PropertyUtilsSharingTest.java
new file mode 100644
index 0000000..74eb4ba
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/PropertyUtilsSharingTest.java
@@ -0,0 +1,68 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml;
+
+import junit.framework.TestCase;
+
+import org.junit.Test;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.introspector.PropertyUtils;
+import org.yaml.snakeyaml.representer.Representer;
+
+public class PropertyUtilsSharingTest extends TestCase {
+
+ public void testYamlDefaults() {
+ Yaml yaml1 = new Yaml();
+ assertSame(yaml1.constructor.getPropertyUtils(), yaml1.representer.getPropertyUtils());
+
+ Yaml yaml2 = new Yaml(new Constructor());
+ assertSame(yaml2.constructor.getPropertyUtils(), yaml2.representer.getPropertyUtils());
+
+ Yaml yaml3 = new Yaml(new Representer());
+ assertSame(yaml3.constructor.getPropertyUtils(), yaml3.representer.getPropertyUtils());
+ }
+
+ public void testYamlConstructorWithPropertyUtils() {
+ Constructor constructor1 = new Constructor();
+ PropertyUtils pu = new PropertyUtils();
+ constructor1.setPropertyUtils(pu);
+ Yaml yaml = new Yaml(constructor1);
+ assertSame(pu, yaml.constructor.getPropertyUtils());
+ assertSame(pu, yaml.representer.getPropertyUtils());
+ }
+
+ public void testYamlRepresenterWithPropertyUtils() {
+ Representer representer2 = new Representer();
+ PropertyUtils pu = new PropertyUtils();
+ representer2.setPropertyUtils(pu);
+ Yaml yaml = new Yaml(representer2);
+ assertSame(pu, yaml.constructor.getPropertyUtils());
+ assertSame(pu, yaml.representer.getPropertyUtils());
+ }
+
+ @Test
+ public void testYamlConstructorANDRepresenterWithPropertyUtils() {
+ Constructor constructor = new Constructor();
+ PropertyUtils pu_c = new PropertyUtils();
+ constructor.setPropertyUtils(pu_c);
+ Representer representer = new Representer();
+ PropertyUtils pu_r = new PropertyUtils();
+ representer.setPropertyUtils(pu_r);
+ Yaml yaml = new Yaml(constructor, representer);
+ assertSame(pu_c, yaml.constructor.getPropertyUtils());
+ assertSame(pu_r, yaml.representer.getPropertyUtils());
+ }
+}
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 0000000..8ae7f64
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/Suit.java
@@ -0,0 +1,20 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+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 0000000..bb0e66b
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/TypeDescriptionTest.java
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.constructor.ArrayTagsTest.CarWithArray;
+import org.yaml.snakeyaml.nodes.Tag;
+
+public class TypeDescriptionTest extends TestCase {
+
+ public void testSetTag() {
+ TypeDescription descr = new TypeDescription(TypeDescriptionTest.class);
+ descr.setTag("!bla");
+ assertEquals(new Tag("!bla"), descr.getTag());
+ descr.setTag(new Tag("!foo"));
+ assertEquals(new Tag("!foo"), 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 0000000..61d9fc3
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/Util.java
@@ -0,0 +1,54 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+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) {
+ try {
+ InputStream input;
+ input = YamlDocument.class.getClassLoader().getResourceAsStream(theName);
+ if (input == null) {
+ throw new RuntimeException("Can not find " + theName);
+ }
+ BufferedInputStream is = new BufferedInputStream(input);
+ StringBuilder buf = new StringBuilder(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");
+ StringBuilder buffer = new StringBuilder();
+ for (int j = 0; j < lines.length; j++) {
+ buffer.append(lines[j]);
+ buffer.append("\n");
+ }
+ return buffer.toString();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/YamlComposeTest.java b/src/test/java/org/yaml/snakeyaml/YamlComposeTest.java
new file mode 100644
index 0000000..c6ac047
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/YamlComposeTest.java
@@ -0,0 +1,68 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml;
+
+import java.io.StringReader;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.nodes.MappingNode;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.NodeId;
+import org.yaml.snakeyaml.nodes.ScalarNode;
+
+public class YamlComposeTest extends TestCase {
+
+ public void testComposeManyDocuments() {
+ try {
+ Yaml yaml = new Yaml();
+ yaml.compose(new StringReader("abc: 56\n---\n123\n---\n456"));
+ fail("YAML contans more then one document.");
+ } catch (Exception e) {
+ assertTrue("<<<" + e.getMessage() + ">>>",
+ e.getMessage().startsWith("expected a single document in the stream"));
+ }
+ }
+
+ public void testComposeFromReader() {
+ Yaml yaml = new Yaml();
+ MappingNode node = (MappingNode) yaml.compose(new StringReader("abc: 56"));
+ ScalarNode node1 = (ScalarNode) node.getValue().get(0).getKeyNode();
+ assertEquals("abc", node1.getValue());
+ ScalarNode node2 = (ScalarNode) node.getValue().get(0).getValueNode();
+ assertEquals("56", node2.getValue());
+ }
+
+ public void testComposeAllFromReader() {
+ Yaml yaml = new Yaml();
+ boolean first = true;
+ for (Node node : yaml.composeAll(new StringReader("abc: 56\n---\n123\n---\n456"))) {
+ if (first) {
+ assertEquals(NodeId.mapping, node.getNodeId());
+ } else {
+ assertEquals(NodeId.scalar, node.getNodeId());
+ }
+ first = false;
+ }
+ }
+
+ public void testComposeAllOneDocument() {
+ Yaml yaml = new Yaml();
+ for (Node node : yaml.composeAll(new StringReader("6"))) {
+ assertEquals(NodeId.scalar, node.getNodeId());
+ }
+ }
+}
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 0000000..fbf5104
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/YamlDocument.java
@@ -0,0 +1,79 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml;
+
+import java.io.ByteArrayOutputStream;
+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();
+ }
+ Yaml yaml = new Yaml(constructor);
+ 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);
+ }
+ // 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/YamlParseTest.java b/src/test/java/org/yaml/snakeyaml/YamlParseTest.java
new file mode 100644
index 0000000..4de8db4
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/YamlParseTest.java
@@ -0,0 +1,80 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml;
+
+import java.io.StringReader;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.events.*;
+import org.yaml.snakeyaml.nodes.Tag;
+
+public class YamlParseTest extends TestCase {
+
+ public void testParse() {
+ Yaml yaml = new Yaml();
+ Event e = null;
+ int counter = 0;
+ for (Event event : yaml.parse(new StringReader("abc: 56"))) {
+ if (e == null) {
+ assertTrue(event instanceof StreamStartEvent);
+ }
+ e = event;
+ counter++;
+ }
+ assertTrue(e instanceof StreamEndEvent);
+ assertEquals(8, counter);
+ }
+
+ public void testParseEvents() {
+ Yaml yaml = new Yaml();
+ Iterator<Event> events = yaml.parse(new StringReader("%YAML 1.1\n---\na")).iterator();
+ assertTrue(events.next() instanceof StreamStartEvent);
+ DocumentStartEvent documentStartEvent = (DocumentStartEvent) events.next();
+ assertTrue(documentStartEvent.getExplicit());
+ assertEquals(DumperOptions.Version.V1_1, documentStartEvent.getVersion());
+ Map<String, String> DEFAULT_TAGS = new HashMap<String, String>();
+ DEFAULT_TAGS.put("!", "!");
+ DEFAULT_TAGS.put("!!", Tag.PREFIX);
+ assertEquals(DEFAULT_TAGS, documentStartEvent.getTags());
+ ScalarEvent scalarEvent = (ScalarEvent) events.next();
+ assertNull(scalarEvent.getAnchor());
+ assertNull(scalarEvent.getTag());
+ assertEquals(new ImplicitTuple(true, false).toString(), scalarEvent.getImplicit().toString());
+ DocumentEndEvent documentEndEvent = (DocumentEndEvent) events.next();
+ assertFalse(documentEndEvent.getExplicit());
+ assertTrue("Unexpected event.", events.next() instanceof StreamEndEvent);
+ assertFalse(events.hasNext());
+ }
+
+ public void testParseManyDocuments() {
+ Yaml yaml = new Yaml();
+ Event e = null;
+ int counter = 0;
+ for (Event event : yaml.parse(new StringReader("abc: 56\n---\n4\n---\nqwe\n"))) {
+ if (e == null) {
+ assertTrue(event instanceof StreamStartEvent);
+ }
+ e = event;
+ counter++;
+ }
+ assertTrue(e instanceof StreamEndEvent);
+ assertEquals(14, counter);
+ }
+}
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 0000000..1ccd4e7
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/YamlStream.java
@@ -0,0 +1,95 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+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>();
+
+ 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<Object> piterator = parsedNativeData.iterator();
+ Iterator<Object> niterator = nativeData.iterator();
+ while (piterator.hasNext()) {
+ Object obj1 = niterator.next();
+ Object obj2 = piterator.next();
+ if (obj1 instanceof Map) {
+ @SuppressWarnings("unchecked")
+ Map<Object, Object> map1 = (Map<Object, Object>) obj1;
+ @SuppressWarnings("unchecked")
+ Map<Object, Object> map2 = (Map<Object, Object>) obj2;
+ if (!map1.keySet().equals(map2.keySet())) {
+ throw new AssertionFailedError("Keyset: " + map1.keySet() + "; but was: "
+ + map2.keySet());
+ }
+ for (Iterator<Object> iterator = map1.keySet().iterator(); iterator.hasNext();) {
+ Object key = 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 0000000..8f71b66
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/YamlTest.java
@@ -0,0 +1,74 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml;
+
+import java.util.Iterator;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.error.YAMLException;
+
+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());
+ }
+
+ /**
+ * Check that documents are parsed only when they are asked to be loaded.
+ */
+ public void testOneDocument() {
+ Yaml yaml = new Yaml();
+ String doc = "--- a\n--- [:]";
+ Iterator<Object> loaded = yaml.loadAll(doc).iterator();
+ assertTrue(loaded.hasNext());
+ Object obj1 = loaded.next();
+ assertEquals("a", obj1);
+ assertTrue(loaded.hasNext());
+ try {
+ loaded.next();
+ fail("Second document is invalid");
+ } catch (Exception e) {
+ assertEquals("while parsing a flow node\n" + " in 'reader', line 2, column 6:\n"
+ + " --- [:]\n" + " ^\n"
+ + "expected the node content, but found Value\n"
+ + " in 'reader', line 2, column 6:\n" + " --- [:]\n" + " ^\n",
+ e.getMessage());
+ }
+ }
+
+ public void testOnlyOneDocument() {
+ Yaml yaml = new Yaml();
+ String doc = "--- a\n--- b";
+ try {
+ yaml.load(doc);
+ fail("It must be only one document.");
+ } catch (YAMLException e) {
+ assertEquals("expected a single document in the stream\n"
+ + " in 'string', line 1, column 5:\n" + " --- a\n" + " ^\n"
+ + "but found another document\n" + " in 'string', line 2, column 1:\n"
+ + " --- b\n" + " ^\n", e.getMessage());
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/array/BooleanArr.java b/src/test/java/org/yaml/snakeyaml/array/BooleanArr.java
new file mode 100644
index 0000000..e465950
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/array/BooleanArr.java
@@ -0,0 +1,41 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.array;
+
+import java.util.Arrays;
+
+public class BooleanArr {
+ private boolean[] bools;
+
+ public BooleanArr() {
+ }
+
+ public BooleanArr(boolean[] bools) {
+ this.bools = bools;
+ }
+
+ public String toString() {
+ return Arrays.toString(bools);
+ }
+
+ public boolean[] getBools() {
+ return bools;
+ }
+
+ public void setBools(boolean[] bools) {
+ this.bools = bools;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/array/ByteArr.java b/src/test/java/org/yaml/snakeyaml/array/ByteArr.java
new file mode 100644
index 0000000..bf8aac5
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/array/ByteArr.java
@@ -0,0 +1,42 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.array;
+
+import java.util.Arrays;
+
+public class ByteArr {
+
+ private byte[] bytes;
+
+ public ByteArr() {
+ }
+
+ public ByteArr(byte[] bytes) {
+ this.bytes = bytes;
+ }
+
+ public String toString() {
+ return Arrays.toString(bytes);
+ }
+
+ public byte[] getBytes() {
+ return bytes;
+ }
+
+ public void setBytes(byte[] bytes) {
+ this.bytes = bytes;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/array/CharArr.java b/src/test/java/org/yaml/snakeyaml/array/CharArr.java
new file mode 100644
index 0000000..7f309ee
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/array/CharArr.java
@@ -0,0 +1,41 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.array;
+
+import java.util.Arrays;
+
+public class CharArr {
+ private char[] chars;
+
+ public CharArr() {
+ }
+
+ public CharArr(char[] chars) {
+ this.chars = chars;
+ }
+
+ public String toString() {
+ return Arrays.toString(chars);
+ }
+
+ public char[] getChars() {
+ return chars;
+ }
+
+ public void setChars(char[] chars) {
+ this.chars = chars;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/array/DoubleArr.java b/src/test/java/org/yaml/snakeyaml/array/DoubleArr.java
new file mode 100644
index 0000000..6b134a3
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/array/DoubleArr.java
@@ -0,0 +1,41 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.array;
+
+import java.util.Arrays;
+
+public class DoubleArr {
+ private double[] doubles;
+
+ public DoubleArr() {
+ }
+
+ public DoubleArr(double[] doubles) {
+ this.doubles = doubles;
+ }
+
+ public String toString() {
+ return Arrays.toString(doubles);
+ }
+
+ public double[] getDoubles() {
+ return doubles;
+ }
+
+ public void setDoubles(double[] doubles) {
+ this.doubles = doubles;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/array/FloatArr.java b/src/test/java/org/yaml/snakeyaml/array/FloatArr.java
new file mode 100644
index 0000000..01f5338
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/array/FloatArr.java
@@ -0,0 +1,41 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.array;
+
+import java.util.Arrays;
+
+public class FloatArr {
+ private float[] floats;
+
+ public FloatArr() {
+ }
+
+ public FloatArr(float[] floats) {
+ this.floats = floats;
+ }
+
+ public String toString() {
+ return Arrays.toString(floats);
+ }
+
+ public float[] getFloats() {
+ return floats;
+ }
+
+ public void setFloats(float[] floats) {
+ this.floats = floats;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/array/IntArr.java b/src/test/java/org/yaml/snakeyaml/array/IntArr.java
new file mode 100644
index 0000000..8ed8e2a
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/array/IntArr.java
@@ -0,0 +1,41 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.array;
+
+import java.util.Arrays;
+
+public class IntArr {
+ private int[] ints;
+
+ public IntArr() {
+ }
+
+ public IntArr(int[] ints) {
+ this.ints = ints;
+ }
+
+ public String toString() {
+ return Arrays.toString(ints);
+ }
+
+ public int[] getInts() {
+ return ints;
+ }
+
+ public void setInts(int[] ints) {
+ this.ints = ints;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/array/LongArr.java b/src/test/java/org/yaml/snakeyaml/array/LongArr.java
new file mode 100644
index 0000000..c20adfe
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/array/LongArr.java
@@ -0,0 +1,41 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.array;
+
+import java.util.Arrays;
+
+public class LongArr {
+ private long[] longs;
+
+ public LongArr() {
+ }
+
+ public LongArr(long[] longs) {
+ this.longs = longs;
+ }
+
+ public String toString() {
+ return Arrays.toString(longs);
+ }
+
+ public long[] getLongs() {
+ return longs;
+ }
+
+ public void setLongs(long[] longs) {
+ this.longs = longs;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/array/PrimitiveArrayTest.java b/src/test/java/org/yaml/snakeyaml/array/PrimitiveArrayTest.java
new file mode 100644
index 0000000..09b1d53
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/array/PrimitiveArrayTest.java
@@ -0,0 +1,255 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.array;
+
+import java.util.Arrays;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.junit.Assert;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.ConstructorException;
+import org.yaml.snakeyaml.error.YAMLException;
+
+public class PrimitiveArrayTest extends TestCase {
+
+ private final String pkg = "!!org.yaml.snakeyaml.array";
+
+ private final byte[] bytes = new byte[] { 1, 2, 3 };
+ private final short[] shorts = new short[] { 300, 301, 302 };
+ private final int[] ints = new int[] { 40000, 40001, 40002 };
+ private final long[] longs = new long[] { 5000000000L, 5000000001L };
+ private final float[] floats = new float[] { 0.1f, 3.1415f };
+ private final double[] doubles = new double[] { 50.0001, 2150.0002 };
+ private final char[] chars = new char[] { 'a', 'b', 'c', 'd', 'e' };
+ private final boolean[] bools = new boolean[] { true, false };
+
+ public void testValidConstructor() {
+ String testInput = "- " + pkg + ".ByteArr [ " + Arrays.toString(bytes) + " ]\n" + "- "
+ + pkg + ".ShortArr [ " + Arrays.toString(shorts) + " ]\n" + "- " + pkg
+ + ".IntArr [ " + Arrays.toString(ints) + " ]\n" + "- " + pkg + ".LongArr [ "
+ + Arrays.toString(longs) + " ]\n" + "- " + pkg + ".FloatArr [ "
+ + Arrays.toString(floats) + " ]\n" + "- " + pkg + ".DoubleArr [ "
+ + Arrays.toString(doubles) + " ]\n" + "- " + pkg + ".CharArr [ "
+ + Arrays.toString(chars) + " ]\n" + "- " + pkg + ".BooleanArr [ "
+ + Arrays.toString(bools) + " ]\n";
+
+ Yaml yaml = new Yaml();
+ List<Object> wrappers = (List<Object>) yaml.load(testInput);
+
+ Assert.assertArrayEquals(bytes, ((ByteArr) wrappers.get(0)).getBytes());
+ Assert.assertArrayEquals(shorts, ((ShortArr) wrappers.get(1)).getShorts());
+ Assert.assertArrayEquals(ints, ((IntArr) wrappers.get(2)).getInts());
+ Assert.assertArrayEquals(longs, ((LongArr) wrappers.get(3)).getLongs());
+ Assert.assertArrayEquals(floats, ((FloatArr) wrappers.get(4)).getFloats(), 0.001f);
+ Assert.assertArrayEquals(doubles, ((DoubleArr) wrappers.get(5)).getDoubles(), 0.001);
+ Assert.assertArrayEquals(chars, ((CharArr) wrappers.get(6)).getChars());
+ assertArrayEquals(bools, ((BooleanArr) wrappers.get(7)).getBools());
+ }
+
+ /*
+ * For some reason, every other assertArrayEquals specialization is provided
+ * by org.junit.Assert, but not this one.
+ */
+ private void assertArrayEquals(boolean[] expected, boolean[] actuals) {
+ assertEquals("Arrays differ in length", expected.length, actuals.length);
+ for (int i = 0; i < expected.length; ++i) {
+ if (expected[i] != actuals[i]) {
+ fail("Arrays first differ at " + i + "; expected " + expected[i] + " but got "
+ + actuals[i]);
+ }
+ }
+ }
+
+ private void tryInvalid(String t, Class<?> expectedException) {
+ Yaml yaml = new Yaml();
+ try {
+ Object loaded = yaml.load(t);
+ fail("Expected " + expectedException.getCanonicalName() + " but loaded = \"" + loaded
+ + "\"");
+ } catch (YAMLException e) {
+ assertEquals(expectedException, e.getCause().getClass());
+ }
+ }
+
+ public void testInvalidConstructors() {
+ // Loading a character as any primitive other than 'char' is a
+ // NumberFormatException
+ tryInvalid(pkg + ".ByteArr [ [ 'a' ] ]", NumberFormatException.class);
+ tryInvalid(pkg + ".ShortArr [ [ 'a' ] ]", NumberFormatException.class);
+ tryInvalid(pkg + ".IntArr [ [ 'a' ] ]", NumberFormatException.class);
+ tryInvalid(pkg + ".LongArr [ [ 'a' ] ]", NumberFormatException.class);
+ tryInvalid(pkg + ".FloatArr [ [ 'a' ] ]", NumberFormatException.class);
+ tryInvalid(pkg + ".DoubleArr [ [ 'a' ] ]", NumberFormatException.class);
+
+ // Exception: because of how boolean construction works, constructing a
+ // boolean from 'a'
+ // results in null.
+ tryInvalid(pkg + ".BooleanArr [ [ 'a' ] ]", NullPointerException.class);
+
+ // Loading a floating-point number as a character is a YAMLException
+ tryInvalid(pkg + ".CharArr [ [ 1.2 ] ]", YAMLException.class);
+
+ // Loading a String as a Character is a YAMLException
+ tryInvalid(pkg + ".CharArr [ [ 'abcd' ] ]", YAMLException.class);
+
+ }
+
+ public void testTruncation() {
+ // Loading floating-point numbers as integer types is disallowed,
+ // because that's a number-format problem.
+ tryInvalid(pkg + ".ByteArr [ [ 3.14 ] ]", NumberFormatException.class);
+ tryInvalid(pkg + ".ShortArr [ [ 3.14 ] ]", NumberFormatException.class);
+ tryInvalid(pkg + ".IntArr [ [ 3.14 ] ]", NumberFormatException.class);
+ tryInvalid(pkg + ".LongArr [ [ 3.14 ] ]", NumberFormatException.class);
+ }
+
+ public void testPromotion() {
+ Yaml yaml = new Yaml();
+
+ // Loading integer numbers as floating-point types is allowed...
+ Assert.assertArrayEquals(new float[] { 3, 5 },
+ ((FloatArr) yaml.load(pkg + ".FloatArr [ [ 3, 5 ] ] ")).getFloats(), 0.001f);
+
+ Assert.assertArrayEquals(new double[] { 3, 5 },
+ ((DoubleArr) yaml.load(pkg + ".DoubleArr [ [ 3, 5 ] ] ")).getDoubles(), 0.001f);
+ }
+
+ public void testStringCharArray() {
+ Yaml yaml = new Yaml();
+
+ try {
+ yaml.load(pkg + ".CharArr [ [ abcd ] ]");
+ fail("Expected exception.");
+ } catch (Exception e) {
+ assertEquals(ConstructorException.class, e.getClass());
+ assertEquals("Invalid node Character: 'abcd'; length: 4", e.getCause().getMessage());
+ }
+ }
+
+ private static Object cycle(Object in) {
+ Yaml yaml = new Yaml();
+ String dumped = yaml.dump(in);
+ // System.out.println ( dumped );
+ return yaml.load(dumped);
+ }
+
+ /**
+ * All kinds of primitive arrays should be able to cycle from (Java array)
+ * to (YAML string) to (Java array) again, and they should be exactly the
+ * same before and after.
+ */
+ public void testCycle() {
+ ByteArr byteArr = new ByteArr(bytes);
+ Assert.assertArrayEquals(byteArr.getBytes(), ((ByteArr) cycle(byteArr)).getBytes());
+
+ ShortArr shortArr = new ShortArr(shorts);
+ Assert.assertArrayEquals(shortArr.getShorts(), ((ShortArr) cycle(shortArr)).getShorts());
+
+ IntArr intArr = new IntArr(ints);
+ Assert.assertArrayEquals(intArr.getInts(), ((IntArr) cycle(intArr)).getInts());
+
+ LongArr longArr = new LongArr(longs);
+ Assert.assertArrayEquals(longArr.getLongs(), ((LongArr) cycle(longArr)).getLongs());
+
+ FloatArr floatArr = new FloatArr(floats);
+ Assert.assertArrayEquals(floatArr.getFloats(), ((FloatArr) cycle(floatArr)).getFloats(),
+ 0.001f);
+
+ DoubleArr doubleArr = new DoubleArr(doubles);
+ Assert.assertArrayEquals(doubleArr.getDoubles(),
+ ((DoubleArr) cycle(doubleArr)).getDoubles(), 0.001);
+
+ CharArr charArr = new CharArr(chars);
+ Assert.assertArrayEquals(charArr.getChars(), ((CharArr) cycle(charArr)).getChars());
+
+ BooleanArr boolArr = new BooleanArr(bools);
+ assertArrayEquals(boolArr.getBools(), ((BooleanArr) cycle(boolArr)).getBools());
+ }
+
+ public void testMultiDimensional() {
+ Array2D two = new Array2D();
+ two.setLongs(new long[][] { { 1, 2, 3 }, { 4, 5, 6 } });
+ assertTrue(Arrays.deepEquals(two.getLongs(), ((Array2D) cycle(two)).getLongs()));
+
+ Array3D three = new Array3D();
+ three.setLongs(new long[][][] { { { 1, 2, 3, 4 }, { 5, 6, 7, 8 } },
+ { { 9, 10, 11, 12 }, { 13, 14, 15, 16 } } });
+ assertTrue(Arrays.deepEquals(three.getLongs(), ((Array3D) cycle(three)).getLongs()));
+
+ // Object with an array of Objects which each have an array of
+ // primitives.
+ ArrayLongArr four = new ArrayLongArr();
+ four.setContents(new LongArr[] { new LongArr(new long[] { 1, 2, 3, 4 }),
+ new LongArr(new long[] { 5, 6, 7, 8 }) });
+ Object result = cycle(four);
+ assertEquals(four, (ArrayLongArr) result);
+ }
+
+ public static class Array2D {
+ private long[][] longs;
+
+ public long[][] getLongs() {
+ return longs;
+ }
+
+ public void setLongs(long[][] longs) {
+ this.longs = longs;
+ }
+ }
+
+ public static class Array3D {
+ private long[][][] longs;
+
+ public long[][][] getLongs() {
+ return longs;
+ }
+
+ public void setLongs(long[][][] longs) {
+ this.longs = longs;
+ }
+ }
+
+ public static class ArrayLongArr {
+ private LongArr[] contents;
+
+ public LongArr[] getContents() {
+ return contents;
+ }
+
+ public void setContents(LongArr[] contents) {
+ this.contents = contents;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof ArrayLongArr))
+ return false;
+
+ ArrayLongArr other = ((ArrayLongArr) obj);
+ if (contents.length != other.getContents().length)
+ return false;
+ for (int i = 0; i < contents.length; ++i) {
+ if (!Arrays.equals(contents[i].getLongs(), other.getContents()[i].getLongs())) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/array/ShortArr.java b/src/test/java/org/yaml/snakeyaml/array/ShortArr.java
new file mode 100644
index 0000000..bd09bbf
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/array/ShortArr.java
@@ -0,0 +1,41 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.array;
+
+import java.util.Arrays;
+
+public class ShortArr {
+ private short[] shorts;
+
+ public ShortArr() {
+ }
+
+ public ShortArr(short[] shorts) {
+ this.shorts = shorts;
+ }
+
+ public String toString() {
+ return Arrays.toString(shorts);
+ }
+
+ public short[] getShorts() {
+ return shorts;
+ }
+
+ public void setShorts(short[] shorts) {
+ this.shorts = shorts;
+ }
+}
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 0000000..038da90
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/composer/ComposerImplTest.java
@@ -0,0 +1,74 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.composer;
+
+import java.io.StringReader;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.nodes.MappingNode;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.NodeId;
+
+public class ComposerImplTest extends TestCase {
+
+ public void testGetNode() {
+ String data = "american:\n - Boston Red Sox";
+ Yaml yaml = new Yaml();
+ Node node = yaml.compose(new StringReader(data));
+ assertNotNull(node);
+ assertTrue(node instanceof MappingNode);
+ String data2 = "---\namerican:\n- Boston Red Sox";
+ Node node2 = yaml.compose(new StringReader(data2));
+ assertNotNull(node2);
+ assertFalse(node.equals(node2));
+ }
+
+ public void testComposeBean() {
+ String data = "!!org.yaml.snakeyaml.composer.ComposerImplTest$BeanToCompose {name: Bill, age: 18}";
+ Yaml yaml = new Yaml();
+ Node node = yaml.compose(new StringReader(data));
+ assertNotNull(node);
+ assertTrue(node instanceof MappingNode);
+ assertEquals(
+ "tag:yaml.org,2002:org.yaml.snakeyaml.composer.ComposerImplTest$BeanToCompose",
+ node.getTag().getValue());
+ assertEquals(NodeId.mapping, node.getNodeId());
+ assertEquals(Object.class, node.getType());
+ }
+
+ public static class BeanToCompose {
+ private String name;
+ private int age;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public int getAge() {
+ return age;
+ }
+
+ public void setAge(int age) {
+ this.age = age;
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/constructor/AbstractConstructTest.java b/src/test/java/org/yaml/snakeyaml/constructor/AbstractConstructTest.java
new file mode 100644
index 0000000..d0c5893
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/constructor/AbstractConstructTest.java
@@ -0,0 +1,59 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.constructor;
+
+import junit.framework.TestCase;
+import org.yaml.snakeyaml.error.YAMLException;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.SequenceNode;
+import org.yaml.snakeyaml.nodes.Tag;
+
+import java.util.ArrayList;
+
+public class AbstractConstructTest extends TestCase {
+
+ public void testNotRecursive() {
+ AbstractConstruct abstractConstruct = new AbstractConstruct() {
+ public Object construct(Node node) {
+ return null;
+ }
+ };
+ Node node = new SequenceNode(Tag.SEQ, true, new ArrayList<Node>(), null, null, false);
+ try {
+ abstractConstruct.construct2ndStep(node, "");
+ fail();
+ } catch (YAMLException e) {
+ assertEquals("Unexpected recursive structure for Node: <org.yaml.snakeyaml.nodes.SequenceNode (tag=tag:yaml.org,2002:seq, value=[])>", e.getMessage());
+ }
+ }
+
+ public void testRecursive() {
+ AbstractConstruct abstractConstruct = new AbstractConstruct() {
+
+ public Object construct(Node node) {
+ return null;
+ }
+ };
+ Node node = new SequenceNode(Tag.SEQ, true, new ArrayList<Node>(), null, null, false);
+ node.setTwoStepsConstruction(true);
+ try {
+ abstractConstruct.construct2ndStep(node, "");
+ fail();
+ } catch (IllegalStateException e) {
+ assertEquals("Not Implemented in org.yaml.snakeyaml.constructor.AbstractConstructTest$2", e.getMessage());
+ }
+ }
+}
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 0000000..ce4e250
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/constructor/ArrayTagsTest.java
@@ -0,0 +1,112 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.constructor;
+
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.DumperOptions.FlowStyle;
+import org.yaml.snakeyaml.TypeDescription;
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+
+public class ArrayTagsTest extends TestCase {
+
+ public void testDefaultRepresenter() {
+ 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-flow-auto.yaml"),
+ new Yaml().dump(car));
+ }
+
+ public void testFlowBlock() {
+ 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);
+ DumperOptions options = new DumperOptions();
+ options.setDefaultFlowStyle(FlowStyle.BLOCK);
+ Yaml yaml = new Yaml(options);
+ assertEquals(Util.getLocalResource("constructor/cararray-with-tags.yaml"), yaml.dump(car));
+ }
+
+ public void testLoadClassTag() {
+ Constructor constructor = new Constructor();
+ constructor.addTypeDescription(new TypeDescription(Car.class, "!car"));
+ Yaml yaml = new Yaml(constructor);
+ 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() {
+ Constructor constructor = new Constructor();
+ try {
+ constructor.addTypeDescription(null);
+ fail("Description is required.");
+ } catch (Exception e) {
+ assertEquals("TypeDescription is required.", e.getMessage());
+ }
+ }
+
+ public void testLoadClassNoRoot() {
+ Constructor constructor = new Constructor(new TypeDescription(CarWithArray.class));
+ Yaml yaml = new Yaml(constructor);
+ 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/AtomicJavaBean.java b/src/test/java/org/yaml/snakeyaml/constructor/AtomicJavaBean.java
new file mode 100644
index 0000000..946ff25
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/constructor/AtomicJavaBean.java
@@ -0,0 +1,44 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.constructor;
+
+import java.util.concurrent.atomic.AtomicLong;
+
+public class AtomicJavaBean {
+ private float amount;
+ private AtomicLong atomic;
+
+ public float getAmount() {
+ return amount;
+ }
+
+ public void setAmount(float amount) {
+ this.amount = amount;
+ }
+
+ public AtomicLong getAtomic() {
+ return atomic;
+ }
+
+ public void setAtomic(AtomicLong atomic) {
+ this.atomic = atomic;
+ }
+
+ @Override
+ public String toString() {
+ return "AtomicJavaBean";
+ }
+}
\ No newline at end of file
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 0000000..d36c733
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/constructor/BeanConstructorTest.java
@@ -0,0 +1,250 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.constructor;
+
+import java.math.BigInteger;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.error.YAMLException;
+
+public class BeanConstructorTest extends TestCase {
+
+ public void testPrimitivesConstructor() {
+ Yaml yaml = new Yaml(new Constructor(TestBean1.class));
+ String document = Util.getLocalResource("constructor/test-primitives1.yaml");
+ 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(Character.valueOf('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.FlowStyle.BLOCK);
+ Yaml yamlToDump = new Yaml(options);
+ String output = yamlToDump.dump(result);
+ TestBean1 result2 = (TestBean1) yaml.load(output);
+ assertNotNull(result2);
+ TestBean1 result3 = (TestBean1) new Yaml().load(output);
+ assertNotNull(result3);
+ }
+
+ public void testNoClassConstructor() {
+ try {
+ new Yaml(new Constructor((Class<? extends Object>) null));
+ fail("Class must be provided.");
+ } catch (NullPointerException e) {
+ assertEquals("Root class must be provided.", e.getMessage());
+ }
+ }
+
+ public void testNoClassConstructorString() throws ClassNotFoundException {
+ try {
+ new Yaml(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 Yaml(new Constructor(" "));
+ fail("Class must be provided.");
+ } catch (YAMLException e) {
+ assertEquals("Root type must be provided.", e.getMessage());
+ }
+ }
+
+ public void testCharacter() {
+ Yaml yaml = new Yaml(new Constructor(TestBean1.class));
+ 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: #";
+ TestBean1 bean = (TestBean1) yaml.load(document);
+ assertNull("Null must be accepted.", bean.getCharClass());
+ document = "charClass: ''";
+ bean = (TestBean1) yaml.load(document);
+ assertNull("Null must be accepted.", bean.getCharClass());
+ document = "charClass:\n";
+ bean = (TestBean1) yaml.load(document);
+ assertNull("Null must be accepted.", bean.getCharClass());
+ document = "charClass: 1\n";
+ bean = (TestBean1) yaml.load(document);
+ assertEquals(Character.valueOf('1'), bean.getCharClass());
+ }
+
+ public void testNoEmptyConstructor() {
+ Yaml yaml = new Yaml(new Constructor(TestBean2.class));
+ String document = "text: qwerty";
+ try {
+ yaml.load(document);
+ fail("No empty constructor available");
+ } catch (Exception e) {
+ assertTrue(e.getMessage(), e.getMessage().contains("NoSuchMethodException"));
+ }
+ TestBean2 bean = new TestBean2();
+ assertEquals("", bean.getText());
+ }
+
+ private class TestBean2 {
+ private String text;
+
+ public TestBean2() {
+ setText("");
+ }
+
+ public String getText() {
+ return text;
+ }
+
+ public void setText(String text) {
+ this.text = text;
+ }
+ }
+
+ public void testPrivateMethod() {
+ // TODO: Are we sure no private ????
+ Yaml yaml = new Yaml(new Constructor(TestBean2.class));
+ String document = "text: qwerty";
+ try {
+ yaml.load(document);
+ fail("Private method cannot be called.");
+ } catch (Exception e) {
+ assertTrue(e.getMessage(), e.getMessage().contains("NoSuchMethodException"));
+ }
+ }
+
+ public void testKeyNotScalar() {
+ Yaml yaml = new Yaml(new Constructor(TestBean1.class));
+ 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() {
+ Yaml yaml = new Yaml(new Constructor(TestBean1.class));
+ 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() {
+ Yaml yaml = new Yaml(new Constructor(TestBean1.class));
+ 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() {
+ Yaml yaml = new Yaml(new Constructor(Parent1.class));
+ 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());
+ }
+
+ public void testScalarContructorException() {
+ Yaml yaml = new Yaml(new Constructor(ExceptionParent.class));
+ String document = "id: 123\nchild: 25";
+ try {
+ yaml.load(document);
+ fail("ExceptionParent should not be created.");
+ } catch (Exception e) {
+ assertTrue(
+ e.getMessage(),
+ e.getMessage().contains(
+ "Can't construct a java object for scalar tag:yaml.org,2002:int"));
+ }
+ }
+
+ static public class ExceptionParent {
+ private String id;
+ private ExceptionChild child;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public ExceptionChild getChild() {
+ return child;
+ }
+
+ public void setChild(ExceptionChild child) {
+ this.child = child;
+ }
+
+ }
+
+ public static class ExceptionChild {
+ private Integer code;
+
+ public ExceptionChild(Integer code) {
+ throw new RuntimeException("ExceptionChild cannot be created.");
+ }
+
+ public Integer getCode() {
+ return code;
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/constructor/BigDecimalBeanConstructorTest.java b/src/test/java/org/yaml/snakeyaml/constructor/BigDecimalBeanConstructorTest.java
new file mode 100644
index 0000000..e5f0fb4
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/constructor/BigDecimalBeanConstructorTest.java
@@ -0,0 +1,58 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.constructor;
+
+import java.math.BigDecimal;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+
+public class BigDecimalBeanConstructorTest extends TestCase {
+
+ public void testRepresentor() {
+ BigDecimalJavaBean bean = new BigDecimalJavaBean();
+ bean.setAmount(1.5f);
+ bean.setNumber(new BigDecimal("3.1416"));
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(bean);
+ String className = this.getClass().getPackage().getName();
+ assertEquals("!!" + className + ".BigDecimalJavaBean {amount: 1.5, number: 3.1416}\n",
+ output);
+ }
+
+ public void testConstructor() {
+ String className = "!!" + this.getClass().getPackage().getName()
+ + ".BigDecimalJavaBean {amount: 1.5, number: 3.1416}";
+ Yaml yaml = new Yaml();
+ BigDecimalJavaBean bean = (BigDecimalJavaBean) yaml.load(className);
+ assertNotNull(bean);
+ assertTrue(1.5 - bean.getAmount() < 0.0000001);
+ assertTrue((new BigDecimal("3.1416")).add(bean.getNumber().negate()).doubleValue() < 0.0000001);
+ }
+
+ public void testConstructorAtomic() {
+ String className = "!!" + this.getClass().getPackage().getName()
+ + ".AtomicJavaBean {amount: 1.5, atomic: 0}";
+ Yaml yaml = new Yaml();
+ try {
+ yaml.load(className);
+ fail("AtomicLong is not supported.");
+ } catch (Exception e) {
+ assertEquals("argument type mismatch", e.getCause().getMessage());
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/constructor/BigDecimalJavaBean.java b/src/test/java/org/yaml/snakeyaml/constructor/BigDecimalJavaBean.java
new file mode 100644
index 0000000..516f4cd
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/constructor/BigDecimalJavaBean.java
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.constructor;
+
+import java.math.BigDecimal;
+
+public class BigDecimalJavaBean {
+ private BigDecimal number;
+ private float amount;
+
+ public BigDecimal getNumber() {
+ return number;
+ }
+
+ public void setNumber(BigDecimal number) {
+ this.number = number;
+ }
+
+ public float getAmount() {
+ return amount;
+ }
+
+ public void setAmount(float amount) {
+ this.amount = amount;
+ }
+}
\ No newline at end of file
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 0000000..d19a713
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/constructor/Car.java
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+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 0000000..592265c
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/constructor/Child1.java
@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+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 0000000..b14c5e7
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/constructor/ClassTagsTest.java
@@ -0,0 +1,105 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.constructor;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+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.nodes.Tag;
+import org.yaml.snakeyaml.representer.Representer;
+
+public class ClassTagsTest extends TestCase {
+
+ public void testDefaultRepresenter() {
+ Car car = new Car();
+ car.setPlate("12-XP-F4");
+ List<Wheel> wheels = new ArrayList<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() {
+ Car car = new Car();
+ car.setPlate("12-XP-F4");
+ List<Wheel> wheels = new ArrayList<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.addClassTag(Car.class, new Tag("!car"));
+ representer.addClassTag(Wheel.class, Tag.MAP);
+ Yaml yaml = new Yaml(representer);
+ String output = yaml.dump(car);
+ assertEquals(Util.getLocalResource("constructor/car-without-tags.yaml"), output);
+ }
+
+ public void testLoadUnknounClassTag() {
+ 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("Invalid tag: !car"));
+ }
+
+ }
+
+ public void testLoadClassTag() {
+ Constructor constructor = new Constructor();
+ constructor.addTypeDescription(new TypeDescription(Car.class, "!car"));
+ Yaml yaml = new Yaml(constructor);
+ String source = Util.getLocalResource("constructor/car-without-tags.yaml");
+ Car car = (Car) yaml.load(source);
+ assertEquals("12-XP-F4", car.getPlate());
+ List<Wheel> wheels = car.getWheels();
+ assertNotNull(wheels);
+ assertEquals(5, wheels.size());
+ }
+
+ public void testNullDescription() {
+ Constructor constructor = new Constructor();
+ try {
+ constructor.addTypeDescription(null);
+ fail("Description is required.");
+ } catch (Exception e) {
+ assertEquals("TypeDescription is required.", e.getMessage());
+ }
+ }
+
+ public void testLoadClassNoRoot() {
+ Constructor constructor = new Constructor(new TypeDescription(Car.class));
+ Yaml yaml = new Yaml(constructor);
+ 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 0000000..7d6b1f3
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/constructor/ConstructorMappingTest.java
@@ -0,0 +1,67 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.constructor;
+
+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.StreamReader;
+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 testGetArrayList() {
+ 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) {
+ StreamReader reader = new StreamReader(data);
+ Parser parser = new ParserImpl(reader);
+ Resolver resolver = new Resolver();
+ Composer composer = new Composer(parser, resolver);
+ constructor.setComposer(composer);
+ return constructor.getSingleData(Object.class);
+ }
+
+ 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 0000000..2641201
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/constructor/ConstructorSequenceTest.java
@@ -0,0 +1,85 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.constructor;
+
+import java.util.ArrayList;
+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.StreamReader;
+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 testGetArrayList() {
+ String data = "[ 1, 2, 3 ]";
+ List<Object> list = construct(data);
+ assertNotNull(list);
+ assertTrue(list.getClass().toString(), list instanceof ArrayList<?>);
+ }
+
+ 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) {
+ StreamReader reader = new StreamReader(data);
+ Parser parser = new ParserImpl(reader);
+ Resolver resolver = new Resolver();
+ Composer composer = new Composer(parser, resolver);
+ constructor.setComposer(composer);
+ List<Object> result = (List<Object>) constructor.getSingleData(Object.class);
+ 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 0000000..47f9805
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/constructor/ConstructorTest.java
@@ -0,0 +1,120 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.constructor;
+
+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"));
+ }
+
+ public void testWrongName() {
+ try {
+ construct("--- !!org.yaml.snakeyaml.constructor.TestBean\nwrongName: No one\nage: 24\nborn: 1982-05-03\n");
+ fail("IntrospectionException expected.");
+ } catch (Exception e) {
+ // TODO improve the error message - the pointer should be at the
+ // property name, not value
+ assertEquals(
+ "Cannot create property=wrongName for JavaBean=#<org.jvyaml.TestBean name=\"null\" age=0 born=\"null\">\n"
+ + " in 'string', line 1, column 5:\n"
+ + " --- !!org.yaml.snakeyaml.constructor ... \n"
+ + " ^\n"
+ + "Unable to find property 'wrongName' on class: org.yaml.snakeyaml.constructor.TestBean\n"
+ + " in 'string', line 2, column 12:\n"
+ + " wrongName: No one\n"
+ + " ^\n", e.getMessage());
+ }
+ }
+
+ private Object construct(String data) {
+ Yaml yaml = new Yaml();
+ return yaml.load(data);
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/constructor/CustomClassLoaderConstructorTest.java b/src/test/java/org/yaml/snakeyaml/constructor/CustomClassLoaderConstructorTest.java
new file mode 100644
index 0000000..c236e23
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/constructor/CustomClassLoaderConstructorTest.java
@@ -0,0 +1,83 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.constructor;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+
+public class CustomClassLoaderConstructorTest extends TestCase {
+
+ public void testGetClassForNameNull() {
+ try {
+ new CustomClassLoaderConstructor(null);
+ fail();
+ } catch (Exception e) {
+ assertEquals("Loader must be provided.", e.getMessage());
+ }
+ }
+
+ public void testGetClassForName() {
+ CustomClassLoaderConstructor constr = new CustomClassLoaderConstructor(
+ CustomClassLoaderConstructorTest.class.getClassLoader());
+ Yaml yaml = new Yaml(constr);
+ String s = (String) yaml.load("abc");
+ assertEquals("abc", s);
+ }
+
+ public void testGetClassForNameWithRoot() throws ClassNotFoundException {
+ Class<?> clazz = Class.forName(
+ "org.yaml.snakeyaml.constructor.CustomClassLoaderConstructorTest$LoaderBean", true,
+ CustomClassLoaderConstructorTest.class.getClassLoader());
+ CustomClassLoaderConstructor constr = new CustomClassLoaderConstructor(clazz,
+ CustomClassLoaderConstructorTest.class.getClassLoader());
+ Yaml yaml = new Yaml(constr);
+ LoaderBean bean = (LoaderBean) yaml.load("{name: Andrey, number: 555}");
+ assertEquals("Andrey", bean.getName());
+ assertEquals(555, bean.getNumber());
+ }
+
+ public void testGetClassForNameBean() {
+ CustomClassLoaderConstructor constr = new CustomClassLoaderConstructor(
+ CustomClassLoaderConstructorTest.class.getClassLoader());
+ Yaml yaml = new Yaml(constr);
+ LoaderBean bean = (LoaderBean) yaml
+ .load("!!org.yaml.snakeyaml.constructor.CustomClassLoaderConstructorTest$LoaderBean {name: Andrey, number: 555}");
+ assertEquals("Andrey", bean.getName());
+ assertEquals(555, bean.getNumber());
+ }
+
+ public static class LoaderBean {
+ private String name;
+ private int number;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public int getNumber() {
+ return number;
+ }
+
+ public void setNumber(int number) {
+ this.number = number;
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/constructor/FilterClassesConstructorTest.java b/src/test/java/org/yaml/snakeyaml/constructor/FilterClassesConstructorTest.java
new file mode 100644
index 0000000..734a58e
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/constructor/FilterClassesConstructorTest.java
@@ -0,0 +1,74 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.constructor;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+
+public class FilterClassesConstructorTest extends TestCase {
+
+ public void testGetClassForName() {
+ Yaml yaml = new Yaml(new FilterConstructor(true));
+ String input = "!!org.yaml.snakeyaml.constructor.FilterClassesConstructorTest$FilteredBean {name: Andrey, number: 543}";
+ try {
+ yaml.load(input);
+ fail("Filter is expected.");
+ } catch (Exception e) {
+ assertTrue(e.getMessage().contains("Filter is applied."));
+ }
+ yaml = new Yaml(new FilterConstructor(false));
+ FilteredBean s = (FilteredBean) yaml.load(input);
+ assertEquals("Andrey", s.getName());
+ }
+
+ class FilterConstructor extends Constructor {
+ private boolean filter;
+
+ public FilterConstructor(boolean f) {
+ filter = f;
+ }
+
+ @Override
+ protected Class<?> getClassForName(String name) throws ClassNotFoundException {
+ if (filter && name.startsWith("org.yaml")) {
+ throw new RuntimeException("Filter is applied.");
+ }
+ return super.getClassForName(name);
+ }
+ }
+
+ public static class FilteredBean {
+ private String name;
+ private int number;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public int getNumber() {
+ return number;
+ }
+
+ public void setNumber(int number) {
+ this.number = number;
+ }
+ }
+}
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 0000000..0c1482d
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/constructor/ImplicitTagsTest.java
@@ -0,0 +1,159 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.constructor;
+
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.DumperOptions.FlowStyle;
+import org.yaml.snakeyaml.TypeDescription;
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.nodes.Tag;
+import org.yaml.snakeyaml.representer.Representer;
+
+public class ImplicitTagsTest extends TestCase {
+
+ public void testDefaultRepresenter() {
+ 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() {
+ 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");
+ String carYaml1 = new Yaml().dumpAs(car1, Tag.MAP, FlowStyle.AUTO);
+ assertEquals(Util.getLocalResource("constructor/car-without-root-tag.yaml"), carYaml1);
+ //
+ Constructor contructor = new Constructor(CarWithWheel.class);
+ CarWithWheel car2 = (CarWithWheel) new Yaml(contructor).load(carYaml1);
+ String carYaml2 = new Yaml().dumpAs(car2, Tag.MAP, FlowStyle.AUTO);
+ assertEquals(carYaml1, carYaml2);
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testRootMap() {
+ Map<Object, Object> car1 = new LinkedHashMap<Object, Object>();
+ Wheel wheel = new Wheel();
+ wheel.setId(2);
+ Map<String, Integer> map = new HashMap<String, Integer>();
+ map.put("id", 3);
+
+ car1.put("wheel", wheel);
+ car1.put("map", map);
+ car1.put("plate", "12-XP-F4");
+
+ 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() {
+ Constructor constructor = new Constructor();
+ constructor.addTypeDescription(new TypeDescription(Car.class, "!car"));
+ Yaml yaml = new Yaml(constructor);
+ 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());
+ Wheel w1 = wheels.get(0);
+ assertEquals(1, w1.getId());
+ //
+ String carYaml1 = new Yaml().dump(car);
+ assertTrue(carYaml1.startsWith("!!org.yaml.snakeyaml.constructor.Car"));
+ //
+ Representer representer = new Representer();
+ representer.addClassTag(Car.class, new Tag("!car"));
+ yaml = new Yaml(representer);
+ 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/IncompleteBeanConstructorTest.java b/src/test/java/org/yaml/snakeyaml/constructor/IncompleteBeanConstructorTest.java
new file mode 100644
index 0000000..d3c8ba0
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/constructor/IncompleteBeanConstructorTest.java
@@ -0,0 +1,59 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.constructor;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.error.YAMLException;
+
+public class IncompleteBeanConstructorTest extends TestCase {
+
+ public void testRepresentor() {
+ IncompleteJavaBean bean = new IncompleteJavaBean();
+ DumperOptions options = new DumperOptions();
+ options.setAllowReadOnlyProperties(true);
+ Yaml yaml = new Yaml(options);
+ String output = yaml.dump(bean);
+ String className = this.getClass().getPackage().getName();
+ assertEquals("!!" + className + ".IncompleteJavaBean {name: No name}\n", output);
+ }
+
+ public void testConstructor() {
+ String className = "!!" + this.getClass().getPackage().getName()
+ + ".IncompleteJavaBean {number: 2}";
+ Yaml yaml = new Yaml();
+ IncompleteJavaBean bean = (IncompleteJavaBean) yaml.load(className);
+ assertNotNull(bean);
+ assertEquals("No name", bean.getName());
+ assertEquals(2, bean.obtainNumber());
+ }
+
+ public void testConstructor2() {
+ String className = "!!" + this.getClass().getPackage().getName()
+ + ".IncompleteJavaBean {number: 2, name: Bill}";
+ Yaml yaml = new Yaml();
+ try {
+ yaml.load(className);
+ fail("'name' property does not have setter.");
+ } catch (YAMLException e) {
+ assertEquals(
+ "Unable to find property 'name' on class: org.yaml.snakeyaml.constructor.IncompleteJavaBean",
+ e.getCause().getMessage());
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/constructor/IncompleteJavaBean.java b/src/test/java/org/yaml/snakeyaml/constructor/IncompleteJavaBean.java
new file mode 100644
index 0000000..d849680
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/constructor/IncompleteJavaBean.java
@@ -0,0 +1,40 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.constructor;
+
+public class IncompleteJavaBean {
+ private int number;
+ private String name = "No name";
+ private float amount;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setNumber(int number) {
+ this.number = number;
+ amount += number;
+ }
+
+ public int obtainNumber() {
+ return number;
+ }
+
+ @Override
+ public String toString() {
+ return "<IncompleteJavaBean name=" + name + ">";
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/org/yaml/snakeyaml/constructor/MockDateBeanConstructorTest.java b/src/test/java/org/yaml/snakeyaml/constructor/MockDateBeanConstructorTest.java
new file mode 100644
index 0000000..9b8d794
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/constructor/MockDateBeanConstructorTest.java
@@ -0,0 +1,72 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.constructor;
+
+import java.util.Date;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+
+public class MockDateBeanConstructorTest extends TestCase {
+
+ public void testConstructor() {
+ String className = "!!org.yaml.snakeyaml.constructor.MockDateBeanConstructorTest$DateBean {number: 24, date: 2009-07-24}";
+ Yaml yaml = new Yaml();
+ try {
+ yaml.load(className);
+ fail("MockDate cannot be constructed.");
+ } catch (Exception e) {
+ assertEquals(
+ "Cannot construct: 'class org.yaml.snakeyaml.constructor.MockDateBeanConstructorTest$MockDate'",
+ e.getCause().getMessage());
+ }
+ }
+
+ public static class DateBean {
+ private int number;
+ private MockDate date;
+
+ public int getNumber() {
+ return number;
+ }
+
+ public void setNumber(int number) {
+ this.number = number;
+ }
+
+ public MockDate getDate() {
+ return date;
+ }
+
+ public void setDate(MockDate date) {
+ this.date = date;
+ }
+
+ @Override
+ public String toString() {
+ return "<DateBean n=" + number + ">";
+ }
+ }
+
+ public static class MockDate extends Date {
+ private static final long serialVersionUID = 621384692653658062L;
+
+ public MockDate(long date) {
+ throw new RuntimeException("Test error.");
+ }
+ }
+}
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 0000000..4753f3e
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/constructor/MyCar.java
@@ -0,0 +1,49 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+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 0000000..67fbeab
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/constructor/MyWheel.java
@@ -0,0 +1,65 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.constructor;
+
+public class MyWheel implements Comparable<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;
+ }
+
+ public int compareTo(MyWheel arg0) {
+ return new Integer(id).compareTo(new Integer(arg0.id));
+ }
+}
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 0000000..3703dbc
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/constructor/Parent1.java
@@ -0,0 +1,37 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+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 0000000..a681ac8
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/constructor/Person.java
@@ -0,0 +1,63 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+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/PrefixConstructorTest.java b/src/test/java/org/yaml/snakeyaml/constructor/PrefixConstructorTest.java
new file mode 100644
index 0000000..6a6a5e0
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/constructor/PrefixConstructorTest.java
@@ -0,0 +1,136 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.constructor;
+
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.ScalarNode;
+import org.yaml.snakeyaml.nodes.SequenceNode;
+import org.yaml.snakeyaml.nodes.Tag;
+
+/**
+ * Example to process a family of tags with the same prefix with one constructor
+ * (PrefixConstruct)
+ */
+public class PrefixConstructorTest extends TestCase {
+
+ @SuppressWarnings("unchecked")
+ public void test1() {
+ Yaml yaml = new Yaml(new CustomConstructor());
+ String input = "- !org.yaml.Foo 123\n- !org.yaml.Bar 456\n- !org.yaml.Exact 789\n- !Immutable [aaa, bbb]";
+ List<Extra> list = (List<Extra>) yaml.load(input);
+ assertEquals(4, list.size());
+ Extra foo = list.get(0);
+ assertEquals("Foo", foo.getName());
+ assertEquals("123", foo.getValue());
+ //
+ Extra bar = list.get(1);
+ assertEquals("Bar", bar.getName());
+ assertEquals("456", bar.getValue());
+ //
+ Extra item = list.get(2);
+ assertEquals("Item", item.getName());
+ assertEquals("789", item.getValue());
+ //
+ Extra immut = list.get(3);
+ assertEquals("aaa", immut.getName());
+ assertEquals("bbb", immut.getValue());
+ }
+
+ private class CustomConstructor extends SafeConstructor {
+ public CustomConstructor() {
+ // define tags which begin with !org.yaml.
+ String prefix = "!org.yaml.";
+ this.yamlMultiConstructors.put(prefix, new PrefixConstruct(prefix,
+ CustomConstructor.this));
+ this.yamlConstructors.put(null, new ConstructUnknown(CustomConstructor.this));
+ this.yamlConstructors.put(new Tag("!org.yaml.Exact"), new ExactConstruct(
+ CustomConstructor.this));
+ }
+ }
+
+ /**
+ * Process tags which start with '!org.yaml.'
+ */
+ private class PrefixConstruct extends AbstractConstruct {
+ private String prefix;
+ private BaseConstructor con;
+
+ public PrefixConstruct(String prefix, BaseConstructor con) {
+ this.prefix = prefix;
+ this.con = con;
+ }
+
+ public Object construct(Node node) {
+ String suffix = node.getTag().getValue().substring(prefix.length());
+ return new Extra(suffix, con.constructScalar((ScalarNode) node).toString());
+ }
+ }
+
+ /**
+ * This has more priority then PrefixConstruct
+ */
+ private class ExactConstruct extends AbstractConstruct {
+ private BaseConstructor con;
+
+ public ExactConstruct(BaseConstructor con) {
+ this.con = con;
+ }
+
+ public Object construct(Node node) {
+ return new Extra("Item", con.constructScalar((ScalarNode) node).toString());
+ }
+ }
+
+ /**
+ * Process unrecognised tags
+ */
+ private class ConstructUnknown extends AbstractConstruct {
+ private BaseConstructor con;
+
+ public ConstructUnknown(BaseConstructor con) {
+ this.con = con;
+ }
+
+ @SuppressWarnings("unchecked")
+ public Object construct(Node node) {
+ List<String> list = (List<String>) con.constructSequence((SequenceNode) node);
+ return new Extra(list.get(0), list.get(1));
+ }
+ }
+
+ private class Extra {
+ private String name;
+ private String value;
+
+ public Extra(String name, String value) {
+ this.name = name;
+ this.value = value;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public String getName() {
+ return name;
+ }
+ }
+}
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 0000000..32fb36f
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/constructor/SafeConstructorTest.java
@@ -0,0 +1,50 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.constructor;
+
+import junit.framework.TestCase;
+
+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 SafeConstructor());
+ assertEquals(3.1416, yaml.load("+3.1416"));
+ }
+
+ public void testSafeConstructJavaBean() {
+ Yaml yaml = new Yaml(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 0000000..31d9194
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/constructor/TestBean.java
@@ -0,0 +1,83 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+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 0000000..be9cf97
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/constructor/TestBean1.java
@@ -0,0 +1,204 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+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 0000000..8afe3ce
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/constructor/TypeSafeCollectionsTest.java
@@ -0,0 +1,103 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.constructor;
+
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.TypeDescription;
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.nodes.Tag;
+import org.yaml.snakeyaml.representer.Representer;
+
+public class TypeSafeCollectionsTest extends TestCase {
+
+ public void testTypeSafeList() {
+ Constructor constructor = new Constructor(Car.class);
+ TypeDescription carDescription = new TypeDescription(Car.class);
+ carDescription.putListPropertyType("wheels", Wheel.class);
+ constructor.addTypeDescription(carDescription);
+ Yaml yaml = new Yaml(constructor);
+ 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() {
+ Constructor constructor = new Constructor(MyCar.class);
+ TypeDescription carDescription = new TypeDescription(MyCar.class);
+ carDescription.putMapPropertyType("wheels", MyWheel.class, Object.class);
+ constructor.addTypeDescription(carDescription);
+ Yaml yaml = new Yaml(constructor);
+ 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 testWithGlobalTag() {
+ Map<MyWheel, Date> wheels = new TreeMap<MyWheel, Date>();
+ long time = 1248212168084L;
+ for (int i = 1; i < 6; i++) {
+ MyWheel mw = new MyWheel();
+ mw.setId(i);
+ mw.setBrand(mw.getBrand() + String.valueOf(i));
+ wheels.put(mw, new Date(time + i));
+ }
+ MyCar c = new MyCar();
+ c.setPlate("00-FF-Q2");
+ c.setWheels(wheels);
+ Representer representer = new Representer();
+ representer.addClassTag(MyWheel.class, Tag.MAP);
+ Yaml yaml = new Yaml(representer);
+ String output = yaml.dump(c);
+ assertEquals(Util.getLocalResource("javabeans/mycar-with-global-tag1.yaml"), output);
+ // load
+ Yaml beanLoader = new Yaml();
+ MyCar car = beanLoader.loadAs(output, MyCar.class);
+ assertNotNull(car);
+ assertEquals("00-FF-Q2", car.getPlate());
+ assertEquals(5, car.getWheels().size());
+ for (Date d : car.getWheels().values()) {
+ // give a day for any timezone
+ assertTrue(d.before(new Date(time + 1000 * 60 * 60 * 24)));
+ assertTrue(d.after(new Date(time)));
+ }
+ Object wheel = car.getWheels().keySet().iterator().next();
+ assertTrue(wheel instanceof MyWheel);
+ MyWheel w = (MyWheel) wheel;
+ assertEquals(1, w.getId());
+ assertEquals("Pirelli1", w.getBrand());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/constructor/VectorTest.java b/src/test/java/org/yaml/snakeyaml/constructor/VectorTest.java
new file mode 100644
index 0000000..0edb6b9
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/constructor/VectorTest.java
@@ -0,0 +1,46 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.constructor;
+
+import java.util.Vector;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+
+public class VectorTest extends TestCase {
+
+ @SuppressWarnings("unchecked")
+ public void testVector() throws ClassNotFoundException {
+ // Data to serialise
+ Vector<String> srcVector = new Vector<String>();
+ srcVector.add("this");
+ srcVector.add("is");
+ srcVector.add("a");
+ srcVector.add("test");
+ // System.out.println("Source Vector: " + srcVector);
+ Yaml yaml = new Yaml();
+ String instance = yaml.dump(srcVector);
+ //System.out.println("YAML String: " + instance);
+ yaml = new Yaml(new Constructor("java.util.Vector"));
+ // If I try to get a Vector I receive a class cast exception.
+ Vector<String> vector = (Vector<String>) yaml.load(instance);
+ // System.out.println("Vector: " + vector);
+ assertEquals(4, vector.size());
+ assertEquals("this", vector.firstElement());
+ assertEquals("test", vector.lastElement());
+ }
+}
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 0000000..91c740e
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/constructor/Wheel.java
@@ -0,0 +1,56 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+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/EmitterMultiLineTest.java b/src/test/java/org/yaml/snakeyaml/emitter/EmitterMultiLineTest.java
new file mode 100644
index 0000000..77c5d2e
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/emitter/EmitterMultiLineTest.java
@@ -0,0 +1,109 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.emitter;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.DumperOptions.FlowStyle;
+import org.yaml.snakeyaml.Yaml;
+
+public class EmitterMultiLineTest extends TestCase {
+
+ public void testWriteMultiLineLiteral() {
+ String plain = "mama\nmila\nramu";
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(plain);
+ // System.out.println(output);
+ assertEquals("|-\n mama\n mila\n ramu\n", output);
+ String parsed = (String) yaml.load(output);
+ // System.out.println(parsed);
+ assertEquals(plain, parsed);
+ }
+
+ public void testWriteMultiLineList() {
+ String one = "first\nsecond\nthird";
+ String two = "one\ntwo\nthree\n";
+ byte[] binary = { 8, 14, 15, 10, 126, 32, 65, 65, 65 };
+ List<Object> list = new ArrayList<Object>(2);
+ list.add(one);
+ list.add(two);
+ list.add(binary);
+ DumperOptions options = new DumperOptions();
+ options.setDefaultFlowStyle(FlowStyle.BLOCK);
+ Yaml yaml = new Yaml(options);
+ String output = yaml.dump(list);
+ // System.out.println(output);
+ String etalon = "- |-\n first\n second\n third\n- |\n one\n two\n three\n- !!binary |-\n CA4PCn4gQUFB\n";
+ assertEquals(etalon, output);
+ @SuppressWarnings("unchecked")
+ List<Object> parsed = (List<Object>) yaml.load(etalon);
+ assertEquals(3, parsed.size());
+ assertEquals(one, parsed.get(0));
+ assertEquals(two, parsed.get(1));
+ assertEquals(new String(binary), new String((byte[]) parsed.get(2)));
+ }
+
+ public void testWriteMultiLineLiteralWithClipChomping() {
+ String source = "a: 1\nb: |\n mama\n mila\n ramu\n";
+ // System.out.println("Source:\n" + source);
+ Yaml yaml = new Yaml();
+ @SuppressWarnings("unchecked")
+ Map<String, Object> parsed = (Map<String, Object>) yaml.load(source);
+ String value = (String) parsed.get("b");
+ // System.out.println(value);
+ assertEquals("mama\nmila\nramu\n", value);
+ String dumped = yaml.dump(parsed);
+ // System.out.println(dumped);
+ assertEquals("a: 1\nb: |\n mama\n mila\n ramu\n", dumped);
+ }
+
+ public void testWriteMultiLineQuotedInFlowContext() {
+ String source = "{a: 1, b: 'mama\n\n mila\n\n ramu'}\n";
+ // System.out.println("Source:\n" + source);
+ DumperOptions options = new DumperOptions();
+ options.setDefaultFlowStyle(FlowStyle.FLOW);
+ Yaml yaml = new Yaml(options);
+ @SuppressWarnings("unchecked")
+ Map<String, Object> parsed = (Map<String, Object>) yaml.load(source);
+ String value = (String) parsed.get("b");
+ // System.out.println(value);
+ assertEquals("mama\nmila\nramu", value);
+ String dumped = yaml.dump(parsed);
+ // System.out.println(dumped);
+ assertEquals("{a: 1, b: \"mama\\nmila\\nramu\"}\n", dumped);
+ }
+
+ public void testWriteMultiLineLiteralWithStripChomping() {
+ String source = "a: 1\nb: |-\n mama\n mila\n ramu\n";
+ // System.out.println("Source:\n" + source);
+ DumperOptions options = new DumperOptions();
+ options.setDefaultFlowStyle(FlowStyle.BLOCK);
+ Yaml yaml = new Yaml(options);
+ @SuppressWarnings("unchecked")
+ Map<String, Object> parsed = (Map<String, Object>) yaml.load(source);
+ String value = (String) parsed.get("b");
+ // System.out.println(value);
+ assertEquals("mama\nmila\nramu", value);
+ String dumped = yaml.dump(parsed);
+ // System.out.println(dumped);
+ assertEquals(source, dumped);
+ }
+}
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 0000000..b50310e
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/emitter/EmitterTest.java
@@ -0,0 +1,263 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.emitter;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.DumperOptions.FlowStyle;
+import org.yaml.snakeyaml.DumperOptions.ScalarStyle;
+import org.yaml.snakeyaml.events.DocumentStartEvent;
+import org.yaml.snakeyaml.events.ImplicitTuple;
+import org.yaml.snakeyaml.events.ScalarEvent;
+import org.yaml.snakeyaml.events.StreamStartEvent;
+
+public class EmitterTest extends TestCase {
+
+ public void testWriteFolded() {
+ DumperOptions options = new DumperOptions();
+ options.setDefaultScalarStyle(ScalarStyle.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.setDefaultScalarStyle(ScalarStyle.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);
+ 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.setDefaultScalarStyle(ScalarStyle.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: |-\n 0123456789 0123456789\n 0123456789 0123456789\nbbb: |2-\n\n bla-bla\n";
+ assertEquals(etalon, output);
+ }
+
+ public void testWritePlainPretty() {
+ DumperOptions options = new DumperOptions();
+ options.setDefaultScalarStyle(ScalarStyle.PLAIN);
+ options.setPrettyFlow(true);
+
+ 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: |-\n 0123456789 0123456789\n 0123456789 0123456789\nbbb: |2-\n\n bla-bla\n";
+ assertEquals(etalon, output);
+ }
+
+ public void testWriteSingleQuoted() {
+ DumperOptions options = new DumperOptions();
+ options.setDefaultScalarStyle(ScalarStyle.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.setDefaultScalarStyle(ScalarStyle.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);
+ }
+
+ // Issue #158
+ public void testWriteSupplementaryUnicode() throws IOException {
+ DumperOptions options = new DumperOptions();
+ String burger = new String(Character.toChars(0x1f354));
+ String halfBurger = "\uD83C";
+ StringWriter output = new StringWriter();
+ Emitter emitter = new Emitter(output, options);
+
+ emitter.emit(new StreamStartEvent(null, null));
+ emitter.emit(new DocumentStartEvent(null, null, false, null, null));
+ emitter.emit(new ScalarEvent(null, null, new ImplicitTuple(true, false), burger
+ + halfBurger, null, null, '"'));
+ String expected = "! \"\\U0001f354\\ud83c\"";
+ assertEquals(expected, output.toString());
+ }
+
+ public void testSplitLineExpectFirstFlowSequenceItem() {
+
+ DumperOptions options = new DumperOptions();
+ options.setDefaultScalarStyle(DumperOptions.ScalarStyle.DOUBLE_QUOTED);
+ options.setDefaultFlowStyle(DumperOptions.FlowStyle.FLOW);
+ options.setWidth(8);
+ Yaml yaml;
+ String output;
+ Map<String, Object> map = new TreeMap<String, Object>();
+ map.put("12345", Arrays.asList("1111111111"));
+
+ // Split lines enabled (default)
+ yaml = new Yaml(options);
+ output = yaml.dump(map);
+ assertEquals("{\"12345\": [\n \"1111111111\"]}\n", output);
+
+ // Split lines disabled
+ options.setSplitLines(false);
+ assertFalse(options.getSplitLines());
+ yaml = new Yaml(options);
+ output = yaml.dump(map);
+ assertEquals("{\"12345\": [\"1111111111\"]}\n", output);
+ }
+
+ public void testWriteIndicatorIndent() {
+ DumperOptions options = new DumperOptions();
+ options.setIndent(5);
+ options.setIndicatorIndent(2);
+ options.setDefaultFlowStyle(FlowStyle.BLOCK);
+ List<?> topLevel = Arrays.asList(Collections.singletonMap("k1", "v1"), Collections.singletonMap("k2", "v2"));
+ Map<String, ?> map = Collections.singletonMap("aaa", topLevel);
+ Yaml yaml = new Yaml(options);
+ String output = yaml.dump(map);
+ String etalon = "aaa:\n - k1: v1\n - k2: v2\n";
+ assertEquals(etalon, output);
+ }
+
+ public void testSplitLineExpectFlowSequenceItem() {
+
+ DumperOptions options = new DumperOptions();
+ options.setDefaultScalarStyle(DumperOptions.ScalarStyle.DOUBLE_QUOTED);
+ options.setDefaultFlowStyle(DumperOptions.FlowStyle.FLOW);
+ options.setWidth(8);
+ Yaml yaml;
+ String output;
+
+ // Split lines enabled (default)
+ yaml = new Yaml(options);
+ output = yaml.dump(Arrays.asList("1111111111", "2222222222"));
+ assertEquals("[\"1111111111\",\n \"2222222222\"]\n", output);
+ output = yaml.dump(Arrays.asList("1", "2"));
+ assertEquals("[\"1\", \"2\"]\n", output);
+
+ // Split lines disabled
+ options.setSplitLines(false);
+ assertFalse(options.getSplitLines());
+ yaml = new Yaml(options);
+ output = yaml.dump(Arrays.asList("1111111111", "2222222222"));
+ assertEquals("[\"1111111111\", \"2222222222\"]\n", output);
+ output = yaml.dump(Arrays.asList("1", "2"));
+ assertEquals("[\"1\", \"2\"]\n", output);
+ }
+
+ public void testSplitLineExpectFirstFlowMappingKey() {
+ DumperOptions options = new DumperOptions();
+ options.setDefaultScalarStyle(DumperOptions.ScalarStyle.DOUBLE_QUOTED);
+ options.setDefaultFlowStyle(DumperOptions.FlowStyle.FLOW);
+ options.setWidth(16);
+ Yaml yaml;
+ String output;
+ Map<String, String> nonSplitMap = new TreeMap<String, String>();
+ nonSplitMap.put("3", "4");
+ Map<String, Map<String, String>> nonSplitContainerMap = new TreeMap<String, Map<String, String>>();
+ nonSplitContainerMap.put("1 2", nonSplitMap);
+ Map<String, String> splitMap = new TreeMap<String, String>();
+ splitMap.put("3333333333", "4444444444");
+ Map<String, Map<String, String>> splitContainerMap = new TreeMap<String, Map<String, String>>();
+ splitContainerMap.put("1111111111 2222222222", splitMap);
+
+ // Split lines enabled (default)
+ yaml = new Yaml(options);
+ output = yaml.dump(splitContainerMap);
+ assertEquals("{\"1111111111 2222222222\": {\n \"3333333333\": \"4444444444\"}}\n", output);
+ output = yaml.dump(nonSplitContainerMap);
+ assertEquals("{\"1 2\": {\"3\": \"4\"}}\n", output);
+
+ // Split lines disabled
+ options.setSplitLines(false);
+ assertFalse(options.getSplitLines());
+ yaml = new Yaml(options);
+ output = yaml.dump(splitContainerMap);
+ assertEquals("{\"1111111111 2222222222\": {\"3333333333\": \"4444444444\"}}\n", output);
+ output = yaml.dump(nonSplitContainerMap);
+ assertEquals("{\"1 2\": {\"3\": \"4\"}}\n", output);
+ }
+
+ public void testSplitLineExpectFlowMappingKey() {
+ DumperOptions options = new DumperOptions();
+ options.setDefaultScalarStyle(DumperOptions.ScalarStyle.DOUBLE_QUOTED);
+ options.setDefaultFlowStyle(DumperOptions.FlowStyle.FLOW);
+ options.setWidth(16);
+ Yaml yaml;
+ String output;
+ Map<String, String> nonSplitMap = new TreeMap<String, String>();
+ nonSplitMap.put("1", "2");
+ nonSplitMap.put("3", "4");
+ Map<String, String> splitMap = new TreeMap<String, String>();
+ splitMap.put("1111111111", "2222222222");
+ splitMap.put("3333333333", "4444444444");
+
+ // Split lines enabled (default)
+ yaml = new Yaml(options);
+ output = yaml.dump(splitMap);
+ assertEquals("{\"1111111111\": \"2222222222\",\n \"3333333333\": \"4444444444\"}\n", output);
+ output = yaml.dump(nonSplitMap);
+ assertEquals("{\"1\": \"2\", \"3\": \"4\"}\n", output);
+
+ // Split lines disabled
+ options.setSplitLines(false);
+ assertFalse(options.getSplitLines());
+ yaml = new Yaml(options);
+ output = yaml.dump(splitMap);
+ assertEquals("{\"1111111111\": \"2222222222\", \"3333333333\": \"4444444444\"}\n", output);
+ output = yaml.dump(nonSplitMap);
+ assertEquals("{\"1\": \"2\", \"3\": \"4\"}\n", 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 0000000..feb773d
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/emitter/EventConstructor.java
@@ -0,0 +1,128 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.emitter;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.yaml.snakeyaml.DumperOptions.Version;
+import org.yaml.snakeyaml.constructor.AbstractConstruct;
+import org.yaml.snakeyaml.constructor.Constructor;
+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.ImplicitTuple;
+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 extends AbstractConstruct {
+
+ @SuppressWarnings("unchecked")
+ public Object construct(Node node) {
+ Map<Object, Object> mapping;
+ if (node instanceof ScalarNode) {
+ mapping = new HashMap<Object, Object>();
+ } else {
+ mapping = constructMapping((MappingNode) node);
+ }
+ String className = node.getTag().getValue().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<Boolean> implicitList = (List<Boolean>) mapping.get("implicit");
+ ImplicitTuple implicit;
+ if (implicitList == null) {
+ implicit = new ImplicitTuple(false, true);
+ } else {
+ implicit = new ImplicitTuple((Boolean) implicitList.get(0),
+ (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");
+ Version version = null;
+ // TODO ???
+ if (versionList != null) {
+ Integer major = versionList.get(0).intValue();
+ if (major != 1) {
+ throw new YAMLException("Unsupported version.");
+ }
+ Integer minor = versionList.get(1).intValue();
+ if (minor == 0) {
+ version = Version.V1_0;
+ } else {
+ version = Version.V1_1;
+ }
+ }
+ 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/template/MyBean.java b/src/test/java/org/yaml/snakeyaml/emitter/template/MyBean.java
new file mode 100644
index 0000000..188c386
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/emitter/template/MyBean.java
@@ -0,0 +1,93 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.emitter.template;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.yaml.snakeyaml.immutable.Point;
+
+public class MyBean {
+ private Point point;
+ private List<String> list;
+ private List<Integer> empty = new ArrayList<Integer>();
+ private String id;
+
+ public Point getPoint() {
+ return point;
+ }
+
+ public void setPoint(Point point) {
+ this.point = point;
+ }
+
+ public List<String> getList() {
+ return list;
+ }
+
+ public void setList(List<String> list) {
+ this.list = list;
+ }
+
+ public List<Integer> getEmpty() {
+ return empty;
+ }
+
+ public void setEmpty(List<Integer> empty) {
+ this.empty = empty;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof MyBean) {
+ MyBean bean = (MyBean) obj;
+ if (!id.equals(bean.id)) {
+ return false;
+ }
+ if (!point.equals(bean.point)) {
+ return false;
+ }
+ if (!list.equals(bean.list)) {
+ return false;
+ }
+ if (!empty.equals(bean.empty)) {
+ return false;
+ }
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return id.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return id;
+ }
+
+}
diff --git a/src/test/java/org/yaml/snakeyaml/emitter/template/VelocityTest.java b/src/test/java/org/yaml/snakeyaml/emitter/template/VelocityTest.java
new file mode 100644
index 0000000..df8b310
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/emitter/template/VelocityTest.java
@@ -0,0 +1,78 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.emitter.template;
+
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.apache.velocity.Template;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.VelocityEngine;
+import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.immutable.Point;
+
+public class VelocityTest extends TestCase {
+ public void testNoTemplate() {
+ DumperOptions options = new DumperOptions();
+ options.setAllowReadOnlyProperties(true);
+ Yaml yaml = new Yaml(options);
+ String output = yaml.dumpAsMap(createBean());
+ // System.out.println(output);
+ assertEquals(Util.getLocalResource("template/etalon1.yaml"), output);
+ }
+
+ public void testTemplate1() throws Exception {
+ VelocityContext context = new VelocityContext();
+ MyBean bean = createBean();
+ context.put("bean", bean);
+ Yaml yaml = new Yaml();
+ context.put("list", yaml.dump(bean.getList()));
+ VelocityEngine ve = new VelocityEngine();
+ ve.setProperty("file.resource.loader.class", ClasspathResourceLoader.class.getName());
+ ve.init();
+ Template t = ve.getTemplate("template/mybean1.vm");
+ StringWriter writer = new StringWriter();
+ t.merge(context, writer);
+ String output = writer.toString().trim().replaceAll("\\r\\n", "\n");
+ // System.out.println(output);
+ String etalon = Util.getLocalResource("template/etalon2-template.yaml").trim();
+ assertEquals(etalon.length(), output.length());
+ assertEquals(etalon, output);
+ // parse the YAML document
+ Yaml loader = new Yaml();
+ MyBean parsedBean = loader.loadAs(output, MyBean.class);
+ assertEquals(bean, parsedBean);
+ }
+
+ private MyBean createBean() {
+ MyBean bean = new MyBean();
+ bean.setId("id123");
+ List<String> list = new ArrayList<String>();
+ list.add("aaa");
+ list.add("bbb");
+ list.add("ccc");
+ bean.setList(list);
+ Point p = new Point(1.0, 2.0);
+ bean.setPoint(p);
+ return bean;
+ }
+}
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 0000000..b67d8fa
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/error/MarkTest.java
@@ -0,0 +1,43 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+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 1, column 1:", lines[0]);
+ assertEquals("*The first line.", lines[1].trim());
+ assertEquals("^", lines[2].trim());
+ }
+
+ public void testPosition() {
+ Mark mark = new Mark("test1", 17, 29, 213, "*The first line.\nThe last line.", 0);
+ assertEquals(17, mark.getIndex());
+ assertEquals(29, mark.getLine());
+ assertEquals(213, mark.getColumn());
+ }
+}
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 0000000..0725db2
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/error/MarkedYAMLExceptionTest.java
@@ -0,0 +1,61 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+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(), 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"));
+ }
+
+ public void testToString3() {
+ MarkedYAMLException exception = new MarkedYAMLException("See http://www.google.com", null,
+ null, null, "Note1");
+ assertTrue(exception.toString().contains("Note1"));
+ }
+
+ public void testToString4() {
+ 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,
+ null, null, null, null);
+ assertTrue(exception.toString().contains("first line"));
+ }
+
+ public void testGetters() {
+ 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);
+ assertEquals("See http://www.google.com", exception.getContext());
+ assertEquals(mark, exception.getContextMark());
+ assertEquals("Error2 happened", exception.getProblem());
+ assertEquals(mark, exception.getProblemMark());
+ }
+}
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 0000000..b167f90
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/events/ScalarEventTest.java
@@ -0,0 +1,35 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.events;
+
+import junit.framework.TestCase;
+
+public class ScalarEventTest extends TestCase {
+
+ public void testToString() {
+ ScalarEvent event = new ScalarEvent("a2", "str", new ImplicitTuple(true, true), "text",
+ null, null, '"');
+ assertEquals(
+ "<org.yaml.snakeyaml.events.ScalarEvent(anchor=a2, tag=str, implicit=[true, true], value=text)>",
+ event.toString());
+ }
+
+ public void testNotEqual() {
+ ScalarEvent event = new ScalarEvent("a2", "str", new ImplicitTuple(true, true), "text",
+ null, null, '"');
+ assertFalse(event.equals(event.toString()));
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/extensions/compactnotation/Box.java b/src/test/java/org/yaml/snakeyaml/extensions/compactnotation/Box.java
new file mode 100644
index 0000000..5bcc036
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/extensions/compactnotation/Box.java
@@ -0,0 +1,53 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.extensions.compactnotation;
+
+public class Box {
+ private String id;
+ private String name;
+ private Item top;
+ private Item bottom;
+
+ public Box(String id, String name) {
+ super();
+ this.id = id;
+ this.name = name;
+ }
+
+ public Item getTop() {
+ return top;
+ }
+
+ public void setTop(Item top) {
+ this.top = top;
+ }
+
+ public Item getBottom() {
+ return bottom;
+ }
+
+ public void setBottom(Item bottom) {
+ this.bottom = bottom;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public String getName() {
+ return name;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/extensions/compactnotation/CompactConstructorErrorsTest.java b/src/test/java/org/yaml/snakeyaml/extensions/compactnotation/CompactConstructorErrorsTest.java
new file mode 100644
index 0000000..161286c
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/extensions/compactnotation/CompactConstructorErrorsTest.java
@@ -0,0 +1,146 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.extensions.compactnotation;
+
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.BaseConstructor;
+import org.yaml.snakeyaml.error.YAMLException;
+
+public class CompactConstructorErrorsTest extends TestCase {
+
+ public void test1() {
+ BaseConstructor compact = new CompactConstructor();
+ Yaml yaml = new Yaml(compact);
+ String doc = Util.getLocalResource("compactnotation/error1.yaml");
+ try {
+ yaml.load(doc);
+ fail("Package is not specified.");
+ } catch (Exception e) {
+ assertEquals("java.lang.ClassNotFoundException: Table", e.getMessage());
+ }
+ }
+
+ private Object load(String fileName) {
+ CompactConstructor compact = new PackageCompactConstructor(
+ "org.yaml.snakeyaml.extensions.compactnotation");
+ Yaml yaml = new Yaml(compact);
+ String doc = Util.getLocalResource("compactnotation/" + fileName);
+ Object obj = yaml.load(doc);
+ assertNotNull(obj);
+ return obj;
+ }
+
+ private void failLoad(String fileName, String failure) {
+ load(fileName);
+ fail(failure);
+ }
+
+ private void check(String fileName, String failure, String message) {
+ check(fileName, failure, message, true);
+ }
+
+ private void check(String fileName, String failure, String message, boolean exactMatch) {
+ try {
+ failLoad(fileName, failure);
+ } catch (YAMLException e) {
+ String eMessage = e.getMessage();
+ if (exactMatch) {
+ assertEquals(message, eMessage);
+ } else {
+ assertNotNull("Exception message is NULL", eMessage);
+ assertTrue(String.format(
+ "\nException message\n%s\ndoes not contain expected value\n%s",
+ e.getMessage(), message), eMessage.contains(message));
+ }
+ } catch (Exception e) {
+ fail("Exception must be YAMLException");
+ }
+ }
+
+ public void test2() {
+ check("error2.yaml",
+ "No single argument constructor provided.",
+ "java.lang.NoSuchMethodException: org.yaml.snakeyaml.extensions.compactnotation.Table.<init>(java.lang.String)");
+ }
+
+ public void test3() {
+ check("error3.yaml",
+ "In-line parameters can only be Strings.",
+ "org.yaml.snakeyaml.error.YAMLException: Cannot set property='size' with value='17' (class java.lang.String) in Row id=id111");
+ }
+
+ /**
+ * Created Map instead of Row
+ */
+ @SuppressWarnings("unchecked")
+ public void test4() {
+ Table table = (Table) load("error4.yaml");
+ List<Row> rows = table.getRows();
+ assertEquals(1, rows.size());
+ assertFalse("Row should not be created.", rows.get(0) instanceof Row);
+ Map<String, String> map = (Map<String, String>) rows.get(0);
+ assertEquals(1, map.size());
+ assertEquals("15}", map.get("Row(id111, description = text) {size"));
+ }
+
+ /**
+ * Wrong indent
+ */
+ @SuppressWarnings("unchecked")
+ public void test5() {
+ Table table = (Table) load("error5.yaml");
+ List<Row> rows = table.getRows();
+ assertEquals(1, rows.size());
+ assertFalse("Row should not be created.", rows.get(0) instanceof Row);
+ Map<String, String> map = (Map<String, String>) rows.get(0);
+ assertEquals(4, map.size());
+ // System.out.println(map);
+ assertNull(map.get(new Row("id222")));
+ assertTrue(map.containsKey(new Row("id222")));
+ assertEquals(17, map.get("size"));
+ }
+
+ public void test6() {
+ check("error6.yaml",
+ "Invalid property.",
+ "org.yaml.snakeyaml.error.YAMLException: Unable to find property 'foo' on class: org.yaml.snakeyaml.extensions.compactnotation.Table");
+ }
+
+ public void test7() {
+ check("error7.yaml",
+ "Invalid property.",
+ "Unable to find property 'foo' on class: org.yaml.snakeyaml.extensions.compactnotation.Table",
+ false);
+ }
+
+ public void test8() {
+ check("error8.yaml",
+ "No list property",
+ "org.yaml.snakeyaml.error.YAMLException: No list property found in class org.yaml.snakeyaml.extensions.compactnotation.Row");
+ }
+
+ public void test9() {
+ check("error9.yaml",
+ "Many list properties found",
+ "org.yaml.snakeyaml.error.YAMLException: Many list properties found in class org.yaml.snakeyaml.extensions.compactnotation.ManyListsTable; Please override getSequencePropertyName() to specify which property to use.");
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/extensions/compactnotation/CompactConstructorExampleTest.java b/src/test/java/org/yaml/snakeyaml/extensions/compactnotation/CompactConstructorExampleTest.java
new file mode 100644
index 0000000..d8e355c
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/extensions/compactnotation/CompactConstructorExampleTest.java
@@ -0,0 +1,180 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.extensions.compactnotation;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.Constructor;
+
+public class CompactConstructorExampleTest extends TestCase {
+
+ private Object load(String fileName) {
+ CompactConstructor compact = new CompactConstructor();
+ Yaml yaml = new Yaml(compact);
+ String doc = Util.getLocalResource("compactnotation/" + fileName);
+ Object obj = yaml.load(doc);
+ assertNotNull(obj);
+ return obj;
+ }
+
+ public void test1() {
+ Object obj = load("example1.yaml");
+ assertEquals(new Container(), obj);
+ }
+
+ public void test2() {
+ Object obj = load("example2.yaml");
+ assertEquals(new Container("title"), obj);
+ }
+
+ public void test3() {
+ Container obj = (Container) load("example3.yaml");
+ assertEquals(new Container("title3"), obj);
+ assertEquals("title3", obj.getTitle());
+ assertEquals("parent", obj.getName());
+ assertEquals("123", obj.getId());
+ }
+
+ public void test4() {
+ Object obj = load("example4.yaml");
+ // System.out.println(obj);
+ Container container = (Container) obj;
+ assertNotNull(obj);
+ assertEquals(new Container("title4"), obj);
+ assertEquals("title4", container.getTitle());
+ assertEquals("child4", container.getName());
+ assertEquals("444", container.getId());
+ }
+
+ public void test5() {
+ Object obj = load("example5.yaml");
+ // System.out.println(obj);
+ Container container = (Container) obj;
+ assertNotNull(obj);
+ assertEquals(new Container("title4"), obj);
+ assertEquals("title4", container.getTitle());
+ assertEquals("child5", container.getName());
+ assertEquals("ID555", container.getId());
+ }
+
+ public void test6() {
+ Object obj = load("example6.yaml");
+ // System.out.println(obj);
+ Container container = (Container) obj;
+ assertNotNull(obj);
+ assertEquals(new Container("title4"), obj);
+ assertEquals("title4", container.getTitle());
+ assertEquals("child6", container.getName());
+ assertEquals("ID6", container.getId());
+ }
+
+ public void test7() {
+ Object obj = load("example7.yaml");
+ // System.out.println(obj);
+ Container container = (Container) obj;
+ assertNotNull(obj);
+ assertEquals(new Container("The title"), obj);
+ assertEquals("The title", container.getTitle());
+ assertEquals("child7", container.getName());
+ assertEquals("id7", container.getId());
+ }
+
+ @SuppressWarnings("unchecked")
+ // TODO it is unclear how the result should look like for CON
+ public void test9() {
+ Map<String, Object> map = (Map<String, Object>) load("example9.yaml");
+ assertEquals(1, map.size());
+ Map<Container, Map<String, String>> containers = (Map<Container, Map<String, String>>) map
+ .get("something");
+ // System.out.println(obj);
+ assertEquals(2, containers.size());
+ for (Container c : containers.keySet()) {
+ assertTrue(c.getId().matches("id\\d"));
+ assertEquals(1, containers.get(c).size());
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public void test10() {
+ Map<String, Object> map = (Map<String, Object>) load("example10.yaml");
+ assertEquals(1, map.size());
+ List<Container> containers = (List<Container>) map.get("something");
+ // System.out.println(obj);
+ assertEquals(3, containers.size());
+ for (Container c : containers) {
+ assertTrue(c.toString(), c.getId().matches("id\\d+"));
+ assertTrue(c.toString(), c.getName().matches("child\\d+"));
+ // System.out.println(c);
+ }
+ }
+
+ public void test11withoutPackageNames() {
+ Constructor compact = new PackageCompactConstructor(
+ "org.yaml.snakeyaml.extensions.compactnotation");
+ Yaml yaml = new Yaml(compact);
+ String doc = Util.getLocalResource("compactnotation/example11.yaml");
+ Box box = (Box) yaml.load(doc);
+ assertNotNull(box);
+ assertEquals("id11", box.getId());
+ assertEquals("Main box", box.getName());
+ Item top = box.getTop();
+ assertEquals("id003", top.getId());
+ assertEquals("25.0", top.getPrice());
+ assertEquals("parrot", top.getName());
+ Item bottom = box.getBottom();
+ assertEquals("id004", bottom.getId());
+ assertEquals("3.5", bottom.getPrice());
+ assertEquals("sweet", bottom.getName());
+ }
+
+ public void test12withList() {
+ Constructor compact = new TableCompactConstructor(
+ "org.yaml.snakeyaml.extensions.compactnotation");
+ Yaml yaml = new Yaml(compact);
+ String doc = Util.getLocalResource("compactnotation/example12.yaml");
+ Table table = (Table) yaml.load(doc);
+ assertNotNull(table);
+ assertEquals("id12", table.getId());
+ assertEquals("A table", table.getName());
+ List<Row> rows = table.getRows();
+ assertEquals(3, rows.size());
+ Iterator<Row> iter = rows.iterator();
+ Row first = iter.next();
+ assertEquals("id111", first.getId());
+ assertEquals("I think; therefore I am.", first.getDescription());
+ assertEquals(0.125, first.getRatio(), 0.000000001);
+ assertEquals(15, first.getSize());
+ Row second = iter.next();
+ assertEquals("id222", second.getId());
+ assertEquals("We do not need new lines here, just replace them all with spaces\n",
+ second.getDescription());
+ assertEquals(0.333, second.getRatio(), 0.000000001);
+ assertEquals(17, second.getSize());
+ Row third = iter.next();
+ assertEquals("id333", third.getId());
+ assertEquals(
+ "Please preserve all\nthe lines because they may be\nimportant, but do not include the last one !!!",
+ third.getDescription());
+ assertEquals(0.88, third.getRatio(), 0.000000001);
+ assertEquals(52, third.getSize());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/extensions/compactnotation/CompactConstructorTest.java b/src/test/java/org/yaml/snakeyaml/extensions/compactnotation/CompactConstructorTest.java
new file mode 100644
index 0000000..837d463
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/extensions/compactnotation/CompactConstructorTest.java
@@ -0,0 +1,112 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.extensions.compactnotation;
+
+import junit.framework.TestCase;
+
+public class CompactConstructorTest extends TestCase {
+
+ public void testNoCompactData() {
+ CompactConstructor flow = new CompactConstructor();
+ assertNull(flow.getCompactData("scalar"));
+ assertNull(flow.getCompactData("123"));
+ assertNull(flow.getCompactData("(name=frame,title=My Frame)"));
+ assertNull(flow.getCompactData("JFrame name=frame,title=My Frame)"));
+ assertNull(flow.getCompactData("JFrame name=frame,title=My Frame"));
+ assertNull(flow.getCompactData("JFrame(name=frame,title=My Frame"));
+ assertNull(flow.getCompactData("JFrame(name=frame,title=My Frame)b"));
+ assertNull(flow.getCompactData("JFrame(name=frame,title=My Frame) "));
+ assertNull(flow.getCompactData("JFrame(name=)"));
+ assertNull(flow.getCompactData("JFrame(=name)"));
+ }
+
+ public void testGetCompactData1() {
+ CompactConstructor flow = new CompactConstructor();
+ CompactData data = flow.getCompactData("JFrame(name=frame)");
+ assertNotNull(data);
+ assertEquals("JFrame", data.getPrefix());
+ assertEquals(1, data.getProperties().size());
+ assertEquals("frame", data.getProperties().get("name"));
+ }
+
+ public void testGetCompactData2() {
+ CompactConstructor flow = new CompactConstructor();
+ CompactData data = flow.getCompactData("Frame(name=frame,title=My Frame)");
+ assertNotNull(data);
+ assertEquals("Frame", data.getPrefix());
+ assertEquals(2, data.getProperties().size());
+ assertEquals("frame", data.getProperties().get("name"));
+ assertEquals("My Frame", data.getProperties().get("title"));
+
+ assertNotNull(flow.getCompactData("JFrame ( name = frame , title = My Frame )"));
+ }
+
+ public void testGetCompactData3() {
+ CompactConstructor flow = new CompactConstructor();
+ CompactData data = flow
+ .getCompactData("JFrame ( name = frame , title = My Frame, number= 123 )");
+ assertNotNull(data);
+ assertEquals("JFrame", data.getPrefix());
+ assertEquals(3, data.getProperties().size());
+ assertEquals("frame", data.getProperties().get("name"));
+ assertEquals("My Frame", data.getProperties().get("title"));
+ assertEquals("123", data.getProperties().get("number"));
+ }
+
+ public void testGetCompactData4() {
+ CompactConstructor flow = new CompactConstructor();
+ CompactData data = flow.getCompactData("JFrame(title)");
+ assertNotNull(data);
+ assertEquals("JFrame", data.getPrefix());
+ assertEquals(0, data.getProperties().size());
+ assertEquals(1, data.getArguments().size());
+ assertEquals("title", data.getArguments().get(0));
+ }
+
+ public void testGetCompactData5() {
+ CompactConstructor flow = new CompactConstructor();
+ CompactData data = flow.getCompactData("JFrame(id123, title, name=foo, alignment=center)");
+ assertNotNull(data);
+ assertEquals("JFrame", data.getPrefix());
+ assertEquals(2, data.getProperties().size());
+ assertEquals(2, data.getArguments().size());
+ assertEquals("id123", data.getArguments().get(0));
+ assertEquals("title", data.getArguments().get(1));
+ }
+
+ public void testGetCompactData6() {
+ CompactConstructor flow = new CompactConstructor();
+ CompactData data = flow.getCompactData("JFrame()");
+ assertNotNull(data);
+ assertEquals("JFrame", data.getPrefix());
+ assertEquals(0, data.getProperties().size());
+ assertEquals(0, data.getArguments().size());
+ }
+
+ public void testGetCompactData7() {
+ CompactConstructor flow = new CompactConstructor();
+ CompactData data = flow.getCompactData("package.Container(name=parent, id=123)");
+ assertNotNull(data);
+ assertEquals("package.Container", data.getPrefix());
+ assertEquals(2, data.getProperties().size());
+ assertEquals(0, data.getArguments().size());
+ }
+
+ public void testCompactDataToString() {
+ CompactData data = new CompactData("foo");
+ assertEquals("CompactData: foo {}", data.toString());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/extensions/compactnotation/Container.java b/src/test/java/org/yaml/snakeyaml/extensions/compactnotation/Container.java
new file mode 100644
index 0000000..56b3c19
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/extensions/compactnotation/Container.java
@@ -0,0 +1,76 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.extensions.compactnotation;
+
+public class Container {
+ private String title;
+ private String name;
+ private String id;
+
+ public Container() {
+ this("no title");
+ }
+
+ public Container(String title) {
+ this.title = title;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof Container) {
+ Container c = (Container) obj;
+ if (name != null && !name.equals(c.name)) {
+ return false;
+ }
+ if (id != null && !id.equals(c.id)) {
+ return false;
+ }
+ return title.equals(c.title);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return title.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return "Container=" + title;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/extensions/compactnotation/Item.java b/src/test/java/org/yaml/snakeyaml/extensions/compactnotation/Item.java
new file mode 100644
index 0000000..d6314c0
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/extensions/compactnotation/Item.java
@@ -0,0 +1,46 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.extensions.compactnotation;
+
+public class Item {
+ private String id;
+ private String price;
+ private String name;
+
+ public Item(String id) {
+ this.id = id;
+ }
+
+ public String getPrice() {
+ return price;
+ }
+
+ public void setPrice(String price) {
+ this.price = price;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getId() {
+ return id;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/extensions/compactnotation/ManyListsTable.java b/src/test/java/org/yaml/snakeyaml/extensions/compactnotation/ManyListsTable.java
new file mode 100644
index 0000000..8b52b2e
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/extensions/compactnotation/ManyListsTable.java
@@ -0,0 +1,48 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.extensions.compactnotation;
+
+import java.util.List;
+
+public class ManyListsTable {
+ private String id;
+ private List<Row> rows;
+ private List<String> names;
+
+ public ManyListsTable(String id) {
+ this.id = id;
+ }
+
+ public List<Row> getRows() {
+ return rows;
+ }
+
+ public void setRows(List<Row> rows) {
+ this.rows = rows;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public List<String> getNames() {
+ return names;
+ }
+
+ public void setNames(List<String> names) {
+ this.names = names;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/extensions/compactnotation/PackageCompactConstructorTest.java b/src/test/java/org/yaml/snakeyaml/extensions/compactnotation/PackageCompactConstructorTest.java
new file mode 100644
index 0000000..551b721
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/extensions/compactnotation/PackageCompactConstructorTest.java
@@ -0,0 +1,50 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.extensions.compactnotation;
+
+import junit.framework.TestCase;
+
+public class PackageCompactConstructorTest extends TestCase {
+
+ public void testGetClassForName() throws ClassNotFoundException {
+ assertEquals(Table.class, check("Table"));
+ assertEquals(Table.class, check("org.yaml.snakeyaml.extensions.compactnotation.Table"));
+ assertEquals(String.class, check("java.lang.String"));
+ }
+
+ public void testException1() throws ClassNotFoundException {
+ try {
+ check("foo.Bar");
+ fail();
+ } catch (ClassNotFoundException e) {
+ assertEquals("foo.Bar", e.getMessage());
+ }
+ }
+
+ public void testException2() throws ClassNotFoundException {
+ try {
+ check("FooBar");
+ fail();
+ } catch (ClassNotFoundException e) {
+ assertEquals("FooBar", e.getMessage());
+ }
+ }
+
+ private Class<?> check(String name) throws ClassNotFoundException {
+ return new PackageCompactConstructor("org.yaml.snakeyaml.extensions.compactnotation")
+ .getClassForName(name);
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/extensions/compactnotation/Row.java b/src/test/java/org/yaml/snakeyaml/extensions/compactnotation/Row.java
new file mode 100644
index 0000000..8e21ad0
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/extensions/compactnotation/Row.java
@@ -0,0 +1,80 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.extensions.compactnotation;
+
+public class Row {
+ private String id;
+ private int size;
+ private double ratio;
+ private float floatRatio;
+ private String description;
+
+ public Row(String id) {
+ super();
+ this.id = id;
+ }
+
+ public int getSize() {
+ return size;
+ }
+
+ public void setSize(int size) {
+ this.size = size;
+ }
+
+ public double getRatio() {
+ return ratio;
+ }
+
+ public void setRatio(double ratio) {
+ this.ratio = ratio;
+ }
+
+ public float getFloatRatio() {
+ return floatRatio;
+ }
+
+ public void setFloatRatio(float floatRatio) {
+ this.floatRatio = floatRatio;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return toString().equals(obj.toString());
+ }
+
+ @Override
+ public int hashCode() {
+ return id.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return "Row id=" + id;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/extensions/compactnotation/Table.java b/src/test/java/org/yaml/snakeyaml/extensions/compactnotation/Table.java
new file mode 100644
index 0000000..dce1eb0
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/extensions/compactnotation/Table.java
@@ -0,0 +1,46 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.extensions.compactnotation;
+
+import java.util.List;
+
+public class Table {
+ private String id;
+ private String name;
+ private List<Row> rows;
+
+ public Table(String id, String name) {
+ super();
+ this.id = id;
+ this.name = name;
+ }
+
+ public List<Row> getRows() {
+ return rows;
+ }
+
+ public void setRows(List<Row> rows) {
+ this.rows = rows;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public String getName() {
+ return name;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/extensions/compactnotation/TableCompactConstructor.java b/src/test/java/org/yaml/snakeyaml/extensions/compactnotation/TableCompactConstructor.java
new file mode 100644
index 0000000..a6e074b
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/extensions/compactnotation/TableCompactConstructor.java
@@ -0,0 +1,24 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.extensions.compactnotation;
+
+public class TableCompactConstructor extends PackageCompactConstructor {
+
+ public TableCompactConstructor(String packageName) {
+ super(packageName);
+ }
+
+}
diff --git a/src/test/java/org/yaml/snakeyaml/generics/AbstractAnimal.java b/src/test/java/org/yaml/snakeyaml/generics/AbstractAnimal.java
new file mode 100644
index 0000000..68452ef
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/generics/AbstractAnimal.java
@@ -0,0 +1,32 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.generics;
+
+public abstract class AbstractAnimal<T> {
+ private String name;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public abstract T getHome();
+
+ public abstract void setHome(T home);
+}
diff --git a/src/test/java/org/yaml/snakeyaml/generics/Bird.java b/src/test/java/org/yaml/snakeyaml/generics/Bird.java
new file mode 100644
index 0000000..0b7bbe8
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/generics/Bird.java
@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.generics;
+
+public class Bird extends AbstractAnimal<Nest> {
+ private Nest home;
+
+ public Nest getHome() {
+ return home;
+ }
+
+ public void setHome(Nest home) {
+ this.home = home;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/generics/BirdTest.java b/src/test/java/org/yaml/snakeyaml/generics/BirdTest.java
new file mode 100644
index 0000000..499539f
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/generics/BirdTest.java
@@ -0,0 +1,57 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.generics;
+
+import java.beans.IntrospectionException;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+
+public class BirdTest extends TestCase {
+
+ public void testHome() throws IntrospectionException {
+ Bird bird = new Bird();
+ bird.setName("Eagle");
+ Nest home = new Nest();
+ home = new Nest();
+ home.setHeight(3);
+ bird.setHome(home);
+ Yaml yaml = new Yaml();
+ String output = yaml.dumpAsMap(bird);
+ Bird parsed;
+ String javaVendor = System.getProperty("java.vm.name");
+ Yaml loader = new Yaml();
+ if (GenericsBugDetector.isProperIntrospection()) {
+ // no global tags
+ System.out.println("java.vm.name: " + javaVendor);
+ assertEquals("no global tags must be emitted.", "home:\n height: 3\nname: Eagle\n",
+ output);
+ parsed = loader.loadAs(output, Bird.class);
+
+ } else {
+ // with global tags
+ System.out
+ .println("JDK requires global tags for JavaBean properties with Java Generics. java.vm.name: "
+ + javaVendor);
+ assertEquals("global tags are inevitable here.",
+ "home: !!org.yaml.snakeyaml.generics.Nest\n height: 3\nname: Eagle\n", output);
+ parsed = loader.loadAs(output, Bird.class);
+ }
+ assertEquals(bird.getName(), parsed.getName());
+ assertEquals(bird.getHome().getHeight(), parsed.getHome().getHeight());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/generics/GenericArrayTypeTest.java b/src/test/java/org/yaml/snakeyaml/generics/GenericArrayTypeTest.java
new file mode 100644
index 0000000..e81c137
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/generics/GenericArrayTypeTest.java
@@ -0,0 +1,119 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.generics;
+
+import java.beans.IntrospectionException;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+
+public class GenericArrayTypeTest extends TestCase {
+
+ public void testClasses() throws IntrospectionException {
+ GenericArray ga = new GenericArray();
+ Yaml yaml = new Yaml();
+ String doc = yaml.dump(ga);
+ // System.out.println(doc);
+ String etalon = "!!org.yaml.snakeyaml.generics.GenericArrayTypeTest$GenericArray\n"
+ + "home: [1, 2, 3]\n" + "name: Array3\n";
+ assertEquals(etalon, doc);
+ if (GenericsBugDetector.isProperIntrospection()) {
+ GenericArray parsed = (GenericArray) yaml.load(doc);
+ assertEquals("Array3", parsed.getName());
+ assertEquals(3, parsed.getHome().length);
+ } else {
+ try {
+ yaml.load(doc);
+ } catch (Exception e) {
+ // TODO Check GenericArrayType
+ String message = "Cannot create property=home for JavaBean=org.yaml.snakeyaml.generics.GenericArrayTypeTest$GenericArray";
+ assertTrue(e.getMessage(), e.getMessage().contains(message));
+ }
+ }
+ }
+
+ public static class GenericArray extends AbstractAnimal<Integer[]> {
+ private Integer[] home;
+
+ public GenericArray() {
+ home = new Integer[3];
+ for (int i = 0; i < home.length; i++) {
+ home[i] = i + 1;
+ }
+ setName("Array" + String.valueOf(3));
+ }
+
+ @Override
+ public Integer[] getHome() {
+ return home;
+ }
+
+ @Override
+ public void setHome(Integer[] home) {
+ this.home = home;
+ }
+ }
+
+ public void testJavaBean() throws IntrospectionException {
+ GenericArray ga = new GenericArray();
+ ArrayBean bean = new ArrayBean();
+ bean.setId("ID556677");
+ bean.setGa(ga);
+ Yaml dumper = new Yaml();
+ String doc = dumper.dumpAsMap(bean);
+ // System.out.println(doc);
+ assertEquals(Util.getLocalResource("javabeans/genericArray-1.yaml"), doc);
+ //
+ Yaml beanLoader = new Yaml();
+ if (GenericsBugDetector.isProperIntrospection()) {
+ ArrayBean loaded = beanLoader.loadAs(doc, ArrayBean.class);
+ assertEquals("ID556677", loaded.getId());
+ assertEquals("Array3", loaded.getGa().getName());
+ assertEquals(3, loaded.getGa().getHome().length);
+ } else {
+ try {
+ beanLoader.load(doc);
+ } catch (Exception e) {
+ // TODO Check GenericArrayType
+ String message = "Cannot create property=home for JavaBean=org.yaml.snakeyaml.generics.GenericArrayTypeTest$GenericArray";
+ assertTrue(e.getMessage(), e.getMessage().contains(message));
+ }
+ }
+ }
+
+ public static class ArrayBean {
+ private String id;
+ private GenericArray ga;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public GenericArray getGa() {
+ return ga;
+ }
+
+ public void setGa(GenericArray ga) {
+ this.ga = ga;
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/generics/GenericsBugDetector.java b/src/test/java/org/yaml/snakeyaml/generics/GenericsBugDetector.java
new file mode 100644
index 0000000..ad7f392
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/generics/GenericsBugDetector.java
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.generics;
+
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+
+/**
+ * @see <a href="http://bugs.sun.com/view_bug.do?bug_id=6528714"></a>
+ */
+public class GenericsBugDetector {
+ /**
+ * Check whether the proper class Nest for Bird's property 'home' is
+ * recognized.
+ */
+ public static boolean isProperIntrospection() throws IntrospectionException {
+ for (PropertyDescriptor property : Introspector.getBeanInfo(Bird.class)
+ .getPropertyDescriptors()) {
+ if (property.getName().equals("home")) {
+ return property.getPropertyType() == Nest.class;
+ }
+ }
+ throw new RuntimeException("Bird must contain 'home' property.");
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/generics/Nest.java b/src/test/java/org/yaml/snakeyaml/generics/Nest.java
new file mode 100644
index 0000000..fbf8dbf
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/generics/Nest.java
@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.generics;
+
+public class Nest {
+ private int height;
+
+ public int getHeight() {
+ return height;
+ }
+
+ public void setHeight(int height) {
+ this.height = height;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/generics/ObjectValues.java b/src/test/java/org/yaml/snakeyaml/generics/ObjectValues.java
new file mode 100644
index 0000000..a321910
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/generics/ObjectValues.java
@@ -0,0 +1,49 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.generics;
+
+import java.util.Map;
+
+public class ObjectValues {
+
+ private Object object;
+ private Map<String, Map<Integer, Object>> values;
+ private String[] possible;
+
+ public Object getObject() {
+ return object;
+ }
+
+ public void setObject(Object object) {
+ this.object = object;
+ }
+
+ public void setValues(Map<String, Map<Integer, Object>> values) {
+ this.values = values;
+ }
+
+ public Map<String, Map<Integer, Object>> getValues() {
+ return values;
+ }
+
+ public void setPossible(String[] possible) {
+ this.possible = possible;
+ }
+
+ public String[] getPossible() {
+ return possible;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/generics/ObjectValuesTest.java b/src/test/java/org/yaml/snakeyaml/generics/ObjectValuesTest.java
new file mode 100644
index 0000000..233a03d
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/generics/ObjectValuesTest.java
@@ -0,0 +1,94 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.generics;
+
+import static org.junit.Assert.assertArrayEquals;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+
+public class ObjectValuesTest extends TestCase {
+
+ public void testObjectValues() {
+ ObjectValues ov = new ObjectValues();
+ Integer obj = new Integer(131313);
+ ov.setObject(obj);
+ final Map<String, Map<Integer, Object>> prop2values = new HashMap<String, Map<Integer, Object>>();
+
+ final String[] props = { "prop1", "prop2", "prop3" };
+ for (String name : props) {
+ Map<Integer, Object> values = new HashMap<Integer, Object>();
+ prop2values.put(name, values);
+ for (int i = 0; i < 3; i++) {
+ values.put(i, name + i);
+ }
+ }
+
+ ov.setValues(prop2values);
+ ov.setPossible(props);
+
+ Yaml dumper = new Yaml();
+ String dumpedStr = dumper.dumpAsMap(ov);
+ Yaml loader = new Yaml();
+ ObjectValues ov2 = loader.loadAs(dumpedStr, ObjectValues.class);
+
+ assertEquals(ov.getObject(), ov2.getObject());
+ assertEquals(ov.getValues(), ov2.getValues());
+ assertArrayEquals(ov.getPossible(), ov2.getPossible());
+ ov.getPossible()[0] = ov2.getPossible()[0];
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testObjectValuesWithParam() {
+ ObjectValuesWithParam<String, Integer> ov = new ObjectValuesWithParam<String, Integer>();
+ Integer obj = new Integer(131313);
+ ov.setObject(obj);
+ final Map<String, Map<Integer, Object>> prop2values = new HashMap<String, Map<Integer, Object>>();
+
+ final String[] props = { "prop1", "prop2", "prop3" };
+ for (String name : props) {
+ Map<Integer, Object> values = new HashMap<Integer, Object>();
+ prop2values.put(name, values);
+ for (int i = 0; i < 3; i++) {
+ values.put(i, name + i);
+ }
+ }
+
+ ov.setValues(prop2values);
+ ov.setPossible(props);
+
+ Yaml dumper = new Yaml();
+ String dumpedStr = dumper.dumpAsMap(ov);
+ Yaml loader = new Yaml();
+ ObjectValuesWithParam<String, Integer> ov2 = loader.loadAs(dumpedStr,
+ new ObjectValuesWithParam<String, Integer>().getClass());
+
+ assertEquals(ov.getObject(), ov2.getObject());
+ assertEquals(ov.getValues(), ov2.getValues());
+ assertArrayEquals(ov.getPossible(), ov2.getPossible());
+ // TODO: This actually FAILS. Use of GenericArrays is ..... no words.
+ // assertEquals(ov.getPossible()[0], ov2.getPossible()[0]);
+ try {
+ ov2.getPossible()[0].toString();
+ } catch (Exception e) {
+ assertTrue(e.getMessage(), e.getMessage().startsWith("[Ljava.lang.Object"));
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/generics/ObjectValuesWithParam.java b/src/test/java/org/yaml/snakeyaml/generics/ObjectValuesWithParam.java
new file mode 100644
index 0000000..51c4485
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/generics/ObjectValuesWithParam.java
@@ -0,0 +1,49 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.generics;
+
+import java.util.Map;
+
+public class ObjectValuesWithParam<T, S> {
+
+ private Object object;
+ private Map<T, Map<S, Object>> values;
+ private T[] possible;
+
+ public Object getObject() {
+ return object;
+ }
+
+ public void setObject(Object object) {
+ this.object = object;
+ }
+
+ public void setValues(Map<T, Map<S, Object>> values) {
+ this.values = values;
+ }
+
+ public Map<T, Map<S, Object>> getValues() {
+ return values;
+ }
+
+ public void setPossible(T[] possible) {
+ this.possible = possible;
+ }
+
+ public T[] getPossible() {
+ return possible;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/immutable/Animal.java b/src/test/java/org/yaml/snakeyaml/immutable/Animal.java
new file mode 100644
index 0000000..f7dcb73
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/immutable/Animal.java
@@ -0,0 +1,20 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.immutable;
+
+public interface Animal {
+ public String getName();
+}
diff --git a/src/test/java/org/yaml/snakeyaml/immutable/Code.java b/src/test/java/org/yaml/snakeyaml/immutable/Code.java
new file mode 100644
index 0000000..3ef1de4
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/immutable/Code.java
@@ -0,0 +1,48 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.immutable;
+
+public class Code {
+ private final Integer code;
+
+ public Code(Integer name) {
+ this.code = name;
+ }
+
+ public Integer getCode() {
+ return code;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof Code) {
+ Code code = (Code) obj;
+ return code.equals(code.code);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return code.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return "<Code code=" + code + ">";
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/immutable/Code2.java b/src/test/java/org/yaml/snakeyaml/immutable/Code2.java
new file mode 100644
index 0000000..02fc2e9
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/immutable/Code2.java
@@ -0,0 +1,55 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.immutable;
+
+/**
+ * Two constructors with 1 argument. These immutable objects are not supported.
+ */
+public class Code2 {
+ private final Integer code;
+
+ public Code2(Integer name) {
+ this.code = name;
+ }
+
+ public Code2(String name) {
+ this.code = new Integer(name);
+ }
+
+ public Integer getCode() {
+ return code;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof Code2) {
+ Code2 code = (Code2) obj;
+ return code.equals(code.code);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return code.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return "<Code2 code=" + code + ">";
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/immutable/Code3.java b/src/test/java/org/yaml/snakeyaml/immutable/Code3.java
new file mode 100644
index 0000000..2638532
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/immutable/Code3.java
@@ -0,0 +1,53 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.immutable;
+
+/**
+ * No constructors with 1 argument. These immutable objects are not supported.
+ */
+public class Code3 {
+ private final String name;
+ private final Integer code;
+
+ public Code3(String name, Integer code) {
+ this.code = code;
+ this.name = name;
+ }
+
+ public String getData() {
+ return name + code;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof Code3) {
+ Code3 code = (Code3) obj;
+ return code.equals(code.code);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return code.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return "<Code3 data=" + getData() + ">";
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/immutable/Code4.java b/src/test/java/org/yaml/snakeyaml/immutable/Code4.java
new file mode 100644
index 0000000..71c6828
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/immutable/Code4.java
@@ -0,0 +1,56 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.immutable;
+
+/**
+ * Two constructors with 1 argument. None of them has String as the argument
+ * class.
+ */
+public class Code4 {
+ private final Integer code;
+
+ public Code4(Integer name) {
+ this.code = name;
+ }
+
+ public Code4(Double name) {
+ this.code = new Integer(name.intValue());
+ }
+
+ public Integer getCode() {
+ return code;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof Code4) {
+ Code4 code = (Code4) obj;
+ return code.equals(code.code);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return code.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return "<Code4 code=" + code + ">";
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/immutable/Color.java b/src/test/java/org/yaml/snakeyaml/immutable/Color.java
new file mode 100644
index 0000000..2ac105a
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/immutable/Color.java
@@ -0,0 +1,48 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.immutable;
+
+public class Color {
+ private final String name;
+
+ public Color(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof Color) {
+ Color color = (Color) obj;
+ return name.equals(color.name);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return name.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return "<Color id=" + name + ">";
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/immutable/Dog.java b/src/test/java/org/yaml/snakeyaml/immutable/Dog.java
new file mode 100644
index 0000000..710aab3
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/immutable/Dog.java
@@ -0,0 +1,33 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.immutable;
+
+public class Dog implements Animal {
+ private String name;
+
+ public Dog(String name) {
+ super();
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void bark() {
+ System.out.println("I am a " + name);
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/immutable/DogImmutableTest.java b/src/test/java/org/yaml/snakeyaml/immutable/DogImmutableTest.java
new file mode 100644
index 0000000..90b1ff6
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/immutable/DogImmutableTest.java
@@ -0,0 +1,36 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.immutable;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+
+public class DogImmutableTest extends TestCase {
+
+ public void testDog() {
+ Yaml yaml = new Yaml();
+ Dog loaded = (Dog) yaml.load("!!org.yaml.snakeyaml.immutable.Dog Bulldog");
+ assertEquals("Bulldog", loaded.getName());
+ }
+
+ public void testHouse() {
+ Yaml yaml = new Yaml();
+ HouseBean loaded = (HouseBean) yaml
+ .load("!!org.yaml.snakeyaml.immutable.HouseBean\nanimal: !!org.yaml.snakeyaml.immutable.Dog Bulldog");
+ assertEquals("Bulldog", loaded.getAnimal().getName());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/immutable/HouseBean.java b/src/test/java/org/yaml/snakeyaml/immutable/HouseBean.java
new file mode 100644
index 0000000..edee6b1
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/immutable/HouseBean.java
@@ -0,0 +1,37 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.immutable;
+
+public class HouseBean {
+ private String name;
+ private Animal animal;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Animal getAnimal() {
+ return animal;
+ }
+
+ public void setAnimal(Animal animal) {
+ this.animal = animal;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/immutable/ImmutablesRepresenter.java b/src/test/java/org/yaml/snakeyaml/immutable/ImmutablesRepresenter.java
new file mode 100644
index 0000000..0595731
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/immutable/ImmutablesRepresenter.java
@@ -0,0 +1,82 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.immutable;
+
+import java.awt.Insets;
+import java.awt.Rectangle;
+import java.util.Arrays;
+
+import javax.swing.border.MatteBorder;
+
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.Tag;
+import org.yaml.snakeyaml.representer.Represent;
+import org.yaml.snakeyaml.representer.Representer;
+
+public class ImmutablesRepresenter extends Representer {
+
+ public ImmutablesRepresenter() {
+ super();
+ this.representers.put(java.awt.Color.class, new RepresentColor());
+ this.representers.put(Insets.class, new RepresentInsets());
+ this.representers.put(MatteBorder.class, new RepresentMatteBorder());
+ this.representers.put(Rectangle.class, new RepresentRectangle());
+ }
+
+ class RepresentInsets implements Represent {
+
+ public Node representData(Object data) {
+ Insets insets = (Insets) data;
+ return representSequence(
+ getTag(data.getClass(), new Tag(data.getClass())),
+ Arrays.asList(new Object[] { insets.top, insets.left, insets.bottom,
+ insets.right }), true);
+ }
+
+ }
+
+ class RepresentRectangle implements Represent {
+
+ public Node representData(Object data) {
+ Rectangle rect = (Rectangle) data;
+ return representSequence(getTag(data.getClass(), new Tag(data.getClass())),
+ Arrays.asList(new Object[] { rect.x, rect.y, rect.width, rect.height }), true);
+ }
+
+ }
+
+ class RepresentMatteBorder implements Represent {
+
+ public Node representData(Object data) {
+ MatteBorder mb = (MatteBorder) data;
+ return representSequence(getTag(data.getClass(), new Tag(data.getClass())),
+ Arrays.asList(new Object[] { mb.getBorderInsets(), mb.getMatteColor() }), true);
+ }
+
+ }
+
+ class RepresentColor implements Represent {
+
+ public Node representData(Object data) {
+ java.awt.Color color = (java.awt.Color) data;
+ return representSequence(
+ getTag(data.getClass(), new Tag(data.getClass())),
+ Arrays.asList(new Integer[] { color.getRed(), color.getGreen(),
+ color.getBlue(), color.getAlpha() }), true);
+ }
+
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/immutable/MoreImmutablesTest.java b/src/test/java/org/yaml/snakeyaml/immutable/MoreImmutablesTest.java
new file mode 100644
index 0000000..b96b37a
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/immutable/MoreImmutablesTest.java
@@ -0,0 +1,78 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.immutable;
+
+import java.awt.Color;
+import java.awt.Insets;
+import java.awt.Rectangle;
+
+import javax.swing.BorderFactory;
+import javax.swing.border.MatteBorder;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Yaml;
+
+public class MoreImmutablesTest extends TestCase {
+
+ public void testInsets() {
+ Yaml yaml = new Yaml(new ImmutablesRepresenter());
+ Insets insets = new Insets(10, 20, 30, 40);
+ String dump = yaml.dump(insets);
+ assertEquals("!!java.awt.Insets [10, 20, 30, 40]\n", dump);
+ Object loaded = yaml.load(dump);
+ assertEquals(insets, loaded);
+ }
+
+ public void testAwtColor() {
+ Yaml yaml = new Yaml(new ImmutablesRepresenter());
+ Color color = new Color(10, 20, 30, 40);
+ String dump = yaml.dump(color);
+ assertEquals("!!java.awt.Color [10, 20, 30, 40]\n", dump);
+ Object loaded = yaml.load(dump);
+ assertEquals(color, loaded);
+ }
+
+ public void testRectangle() {
+ Yaml yaml = new Yaml(new ImmutablesRepresenter());
+ Rectangle rect = new Rectangle(10, 20, 30, 40);
+ String dump = yaml.dump(rect);
+ assertEquals("!!java.awt.Rectangle [10, 20, 30, 40]\n", dump);
+ Object loaded = yaml.load(dump);
+ assertEquals(rect, loaded);
+ }
+
+ // matteborder - only with color - no icon
+ public void testMatteBorder() {
+ DumperOptions options = new DumperOptions();
+ options.setWidth(400);
+ Yaml yaml = new Yaml(new ImmutablesRepresenter(), options);
+ Insets insets = new Insets(10, 20, 30, 40);
+ Color color = new Color(100, 150, 200);
+ MatteBorder border = BorderFactory.createMatteBorder(insets.top, insets.left,
+ insets.bottom, insets.right, color);
+ String dump = yaml.dump(border);
+ assertEquals(
+ "!!javax.swing.border.MatteBorder [!!java.awt.Insets [10, 20, 30, 40], !!java.awt.Color [100, 150, 200, 255]]\n",
+ dump);
+ Object loaded = yaml.load(dump);
+ assertTrue(loaded instanceof MatteBorder);
+ MatteBorder loadedBorder = (MatteBorder) loaded;
+ assertEquals(insets, loadedBorder.getBorderInsets());
+ assertEquals(color, loadedBorder.getMatteColor());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/immutable/Point.java b/src/test/java/org/yaml/snakeyaml/immutable/Point.java
new file mode 100644
index 0000000..98312da
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/immutable/Point.java
@@ -0,0 +1,53 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.immutable;
+
+public class Point {
+ private final double x;
+ private final double y;
+
+ public double getX() {
+ return x;
+ }
+
+ public double getY() {
+ return y;
+ }
+
+ public Point(Double x, Double y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ @Override
+ public String toString() {
+ return "<Point x=" + String.valueOf(x) + " y=" + String.valueOf(y) + ">";
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof Point) {
+ return toString().equals(obj.toString());
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return toString().hashCode();
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/immutable/Point2.java b/src/test/java/org/yaml/snakeyaml/immutable/Point2.java
new file mode 100644
index 0000000..89d1c85
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/immutable/Point2.java
@@ -0,0 +1,47 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.immutable;
+
+/**
+ * Two public constructor with 2 argument are present
+ */
+public class Point2 {
+ private final Integer x;
+ private final Integer y;
+
+ public Integer getX() {
+ return x;
+ }
+
+ public Integer getY() {
+ return y;
+ }
+
+ public Point2(Double x, Double y) {
+ this.x = x.intValue();
+ this.y = y.intValue();
+ }
+
+ public Point2(Integer x, Integer y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ @Override
+ public String toString() {
+ return "<Point2 x=" + String.valueOf(x) + " y=" + String.valueOf(y) + ">";
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/immutable/Point3d.java b/src/test/java/org/yaml/snakeyaml/immutable/Point3d.java
new file mode 100644
index 0000000..333de04
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/immutable/Point3d.java
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.immutable;
+
+public class Point3d {
+ private final double z;
+ private final Point point;
+
+ public Point3d(Point point, Double z) {
+ this.point = point;
+ this.z = z;
+ }
+
+ public double getZ() {
+ return z;
+ }
+
+ public Point getPoint() {
+ return point;
+ }
+
+ @Override
+ public String toString() {
+ return "<Point3d point=" + point.toString() + " z=" + String.valueOf(z) + ">";
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/immutable/Shape.java b/src/test/java/org/yaml/snakeyaml/immutable/Shape.java
new file mode 100644
index 0000000..b1f0b41
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/immutable/Shape.java
@@ -0,0 +1,55 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.immutable;
+
+public class Shape {
+ private Color color;
+ private Point point;
+ private Point3d point3d;
+ private Integer id;
+
+ public Point3d getPoint3d() {
+ return point3d;
+ }
+
+ public void setPoint3d(Point3d point3d) {
+ this.point3d = point3d;
+ }
+
+ public void setColor(Color color) {
+ this.color = color;
+ }
+
+ public void setPoint(Point point) {
+ this.point = point;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public Color getColor() {
+ return color;
+ }
+
+ public Point getPoint() {
+ return point;
+ }
+
+ public Integer getId() {
+ return id;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/immutable/ShapeImmutableTest.java b/src/test/java/org/yaml/snakeyaml/immutable/ShapeImmutableTest.java
new file mode 100644
index 0000000..4d8f454
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/immutable/ShapeImmutableTest.java
@@ -0,0 +1,151 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.immutable;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+
+public class ShapeImmutableTest extends TestCase {
+
+ public void testColor() {
+ Yaml yaml = new Yaml();
+ Color loaded = (Color) yaml.load("!!org.yaml.snakeyaml.immutable.Color BLACK");
+ assertEquals("BLACK", loaded.getName());
+ }
+
+ public void testCode() {
+ Yaml yaml = new Yaml();
+ Code loaded = (Code) yaml.load("!!org.yaml.snakeyaml.immutable.Code 123");
+ assertEquals(new Integer(123), loaded.getCode());
+ }
+
+ public void testSuperColor() {
+ Yaml yaml = new Yaml();
+ SuperColor superColor = (SuperColor) yaml
+ .load("!!org.yaml.snakeyaml.immutable.SuperColor [!!org.yaml.snakeyaml.immutable.Color BLACK]");
+ assertEquals("BLACK", superColor.getColor().getName());
+ }
+
+ public void testSuperColorFail() {
+ Yaml yaml = new Yaml();
+ try {
+ yaml.load("!!org.yaml.snakeyaml.immutable.SuperColor BLACK");
+ fail("SuperColor requires Color and not a String.");
+ } catch (Exception e) {
+ assertTrue(e
+ .getMessage()
+ .startsWith(
+ "Can't construct a java object for tag:yaml.org,2002:org.yaml.snakeyaml.immutable.SuperColor; exception=Unsupported class: class org.yaml.snakeyaml.immutable.Color"));
+ }
+ }
+
+ public void testCode2() {
+ Yaml yaml = new Yaml();
+ Code2 code2 = (Code2) yaml.load("!!org.yaml.snakeyaml.immutable.Code2 555");
+ assertEquals(new Integer(555), code2.getCode());
+ }
+
+ public void testCode3() {
+ Yaml yaml = new Yaml();
+ try {
+ yaml.load("!!org.yaml.snakeyaml.immutable.Code3 777");
+ fail("There must be 1 constructor with 1 argument for scalar.");
+ } catch (Exception e) {
+ assertTrue(e
+ .getMessage()
+ .startsWith(
+ "Can't construct a java object for tag:yaml.org,2002:org.yaml.snakeyaml.immutable.Code3; exception=No single argument constructor found for class org.yaml.snakeyaml.immutable.Code3"));
+ }
+ }
+
+ public void testCode4() {
+ Yaml yaml = new Yaml();
+ try {
+ yaml.load("!!org.yaml.snakeyaml.immutable.Code4 777");
+ fail("Constructor with String is required.");
+ } catch (Exception e) {
+ assertEquals(
+ "Can't construct a java object for tag:yaml.org,2002:org.yaml.snakeyaml.immutable.Code4; exception=Can't construct a java object for scalar tag:yaml.org,2002:org.yaml.snakeyaml.immutable.Code4; No String constructor found. Exception=org.yaml.snakeyaml.immutable.Code4.<init>(java.lang.String)\n"
+ + " in 'string', line 1, column 1:\n"
+ + " !!org.yaml.snakeyaml.immutable.C ... \n" + " ^\n",
+ e.getMessage());
+ }
+ }
+
+ public void testPoint() {
+ Yaml yaml = new Yaml();
+ Point loaded = (Point) yaml.load("!!org.yaml.snakeyaml.immutable.Point [1.17, 3.14]");
+ assertEquals(1.17, loaded.getX());
+ assertEquals(3.14, loaded.getY());
+ }
+
+ public void testPointBlock() {
+ Yaml yaml = new Yaml();
+ Point loaded = (Point) yaml.load("!!org.yaml.snakeyaml.immutable.Point\n- 1.17\n- 3.14");
+ assertEquals(1.17, loaded.getX());
+ assertEquals(3.14, loaded.getY());
+ }
+
+ public void testPointOnlyOneArgument() {
+ Yaml yaml = new Yaml();
+ try {
+ yaml.load("!!org.yaml.snakeyaml.immutable.Point\n- 1.17");
+ fail("Two arguments required.");
+ } catch (Exception e) {
+ assertEquals(
+ "Can't construct a java object for tag:yaml.org,2002:org.yaml.snakeyaml.immutable.Point; exception=No suitable constructor with 1 arguments found for class org.yaml.snakeyaml.immutable.Point\n"
+ + " in 'string', line 1, column 1:\n"
+ + " !!org.yaml.snakeyaml.immutable.Point\n" + " ^\n",
+ e.getMessage());
+ }
+ }
+
+ public void testPoint2() {
+ Yaml yaml = new Yaml();
+ Point2 loaded = (Point2) yaml.load("!!org.yaml.snakeyaml.immutable.Point2\n- 1\n- 3");
+ assertEquals(new Integer(1), loaded.getX());
+ assertEquals(new Integer(3), loaded.getY());
+ }
+
+ public void testPoint3d() {
+ Yaml yaml = new Yaml();
+ Point3d loaded = (Point3d) yaml
+ .load("!!org.yaml.snakeyaml.immutable.Point3d [!!org.yaml.snakeyaml.immutable.Point [1.17, 3.14], 345.1]");
+ assertEquals(345.1, loaded.getZ());
+ }
+
+ public void testShape() {
+ Yaml yaml = new Yaml();
+ String source = Util.getLocalResource("immutable/shape1.yaml");
+ Shape loaded = (Shape) yaml.load(source);
+ assertEquals(new Integer(123), loaded.getId());
+ }
+
+ public void testShapeNoTags() {
+ String source = Util.getLocalResource("immutable/shapeNoTags.yaml");
+ Yaml beanLoader = new Yaml();
+ Shape loaded = beanLoader.loadAs(source, Shape.class);
+ assertEquals(new Integer(123), loaded.getId());
+ assertEquals("BLACK", loaded.getColor().getName());
+ assertEquals(1.17, loaded.getPoint().getX());
+ assertEquals(3.14, loaded.getPoint().getY());
+ assertEquals(345.1, loaded.getPoint3d().getZ());
+ assertEquals(1.96, loaded.getPoint3d().getPoint().getX());
+ assertEquals(1.78, loaded.getPoint3d().getPoint().getY());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/immutable/SuperColor.java b/src/test/java/org/yaml/snakeyaml/immutable/SuperColor.java
new file mode 100644
index 0000000..0a24962
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/immutable/SuperColor.java
@@ -0,0 +1,52 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.immutable;
+
+public class SuperColor {
+ private final Color color;
+
+ public SuperColor(Color name) {
+ this.color = name;
+ }
+
+ public Color getName() {
+ return color;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof SuperColor) {
+ SuperColor color = (SuperColor) obj;
+ return color.equals(color.color);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return color.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return "SuperColor color=" + color;
+ }
+
+ public Color getColor() {
+ return color;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/immutable/primitives/BunchOfPrimitives.java b/src/test/java/org/yaml/snakeyaml/immutable/primitives/BunchOfPrimitives.java
new file mode 100644
index 0000000..19008b4
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/immutable/primitives/BunchOfPrimitives.java
@@ -0,0 +1,67 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.immutable.primitives;
+
+public class BunchOfPrimitives {
+ private int primitiveInt;
+ private double primitiveDouble;
+ public boolean primitiveBoolean;
+
+ public BunchOfPrimitives(int primitiveInt, double primitiveDouble, boolean primitiveBoolean) {
+ this.primitiveInt = primitiveInt;
+ this.primitiveDouble = primitiveDouble;
+ this.primitiveBoolean = primitiveBoolean;
+ }
+
+ /**
+ * The number of parameters is the same but the type is different
+ */
+ public BunchOfPrimitives(int i1, int i2, int i3) {
+ this.primitiveInt = i1;
+ }
+
+ public BunchOfPrimitives(long i1, double i2, boolean i3) {
+ this((int) i1, i2, i3);
+ }
+
+ public int getPrimitiveInt() {
+ return primitiveInt;
+ }
+
+ public double getPrimitiveDouble() {
+ return primitiveDouble;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof BunchOfPrimitives) {
+ BunchOfPrimitives bunch = (BunchOfPrimitives) obj;
+ return primitiveInt == bunch.primitiveInt;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return primitiveInt;
+ }
+
+ @Override
+ public String toString() {
+ return "BunchOfPrimitives " + primitiveInt;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/immutable/primitives/ImmutablePrimitivesRepresenter.java b/src/test/java/org/yaml/snakeyaml/immutable/primitives/ImmutablePrimitivesRepresenter.java
new file mode 100644
index 0000000..36745dc
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/immutable/primitives/ImmutablePrimitivesRepresenter.java
@@ -0,0 +1,40 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.immutable.primitives;
+
+import java.util.Arrays;
+
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.Tag;
+import org.yaml.snakeyaml.representer.Represent;
+import org.yaml.snakeyaml.representer.Representer;
+
+public class ImmutablePrimitivesRepresenter extends Representer {
+ public ImmutablePrimitivesRepresenter() {
+ super();
+ this.representers.put(BunchOfPrimitives.class, new RepresentPrimitives());
+ }
+
+ class RepresentPrimitives implements Represent {
+ public Node representData(Object data) {
+ BunchOfPrimitives bunch = (BunchOfPrimitives) data;
+ return representSequence(
+ getTag(data.getClass(), new Tag(data.getClass())),
+ Arrays.asList(new Object[] { bunch.getPrimitiveInt(),
+ bunch.getPrimitiveDouble(), bunch.primitiveBoolean }), true);
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/immutable/primitives/ImmutablePrimitivesTest.java b/src/test/java/org/yaml/snakeyaml/immutable/primitives/ImmutablePrimitivesTest.java
new file mode 100644
index 0000000..801715b
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/immutable/primitives/ImmutablePrimitivesTest.java
@@ -0,0 +1,55 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.immutable.primitives;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.error.YAMLException;
+
+public class ImmutablePrimitivesTest extends TestCase {
+
+ public void testPrimitives() {
+ Yaml yaml = new Yaml(new ImmutablePrimitivesRepresenter());
+ BunchOfPrimitives bunch = new BunchOfPrimitives(10, 40.0, true);
+ String dump = yaml.dump(bunch);
+ assertEquals("!!" + bunch.getClass().getCanonicalName() + " [10, 40.0, true]\n", dump);
+ Object loaded = yaml.load(dump);
+ assertEquals(loaded.toString(), bunch, loaded);
+ }
+
+ public void testPrimitivesLong() {
+ Yaml yaml = new Yaml();
+ String dump = "!!org.yaml.snakeyaml.immutable.primitives.BunchOfPrimitives [10000000000, 40.0, true]";
+ BunchOfPrimitives bunch = (BunchOfPrimitives) yaml.load(dump);
+ assertEquals("Must be truncated.", new Long(10000000000L).intValue(),
+ bunch.getPrimitiveInt());
+ }
+
+ public void testPrimitivesException() {
+ Yaml yaml = new Yaml();
+ String dump = "!!org.yaml.snakeyaml.immutable.primitives.BunchOfPrimitives [10, 40, true]";
+ try {
+ yaml.load(dump);
+ fail();
+ } catch (YAMLException e) {
+ assertTrue(e
+ .getMessage()
+ .startsWith(
+ "Can't construct a java object for tag:yaml.org,2002:org.yaml.snakeyaml.immutable.primitives.BunchOfPrimitives; exception=No suitable constructor with 3 arguments found for class org.yaml.snakeyaml.immutable.primitives.BunchOfPrimitives"));
+ }
+ }
+}
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 0000000..46c6e0d
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/introspector/MethodPropertyTest.java
@@ -0,0 +1,37 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+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/issues/issue10/BasicDumpTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue10/BasicDumpTest.java
new file mode 100644
index 0000000..a16c4e2
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue10/BasicDumpTest.java
@@ -0,0 +1,99 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue10;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+
+public class BasicDumpTest extends TestCase {
+
+ public void testTag() {
+ DataSource base = new DataSource();
+ JDBCDataSource baseJDBC = new JDBCDataSource();
+ baseJDBC.setParent(base);
+
+ ArrayList<DataSource> dataSources = new ArrayList<DataSource>();
+ // trying expected order first
+ dataSources.add(base);
+ dataSources.add(baseJDBC);
+
+ DataSources ds = new DataSources();
+ ds.setDataSources(dataSources);
+
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(ds);
+
+ String etalon = Util.getLocalResource("javabeans/issue10-1.yaml");
+ assertEquals(etalon.trim(), output.trim());
+ Object obj = yaml.load(output);
+ DataSources dsOut = (DataSources) obj;
+ Iterator<DataSource> iter = dsOut.getDataSources().iterator();
+ assertFalse("Must be DataSource.", iter.next() instanceof JDBCDataSource);
+ assertTrue(iter.next() instanceof JDBCDataSource);
+ }
+
+ public void testTag2() {
+ DataSource base = new DataSource();
+ JDBCDataSource baseJDBC = new JDBCDataSource();
+ baseJDBC.setParent(base);
+
+ ArrayList<DataSource> dataSources = new ArrayList<DataSource>();
+ dataSources.add(base);
+ dataSources.add(baseJDBC);
+
+ DataSources ds = new DataSources();
+ ds.setDataSources(dataSources);
+
+ Yaml yaml = new Yaml();
+ String output = yaml.dumpAsMap(ds);
+
+ String etalon = Util.getLocalResource("javabeans/issue10-2.yaml");
+ assertEquals(etalon.trim(), output.trim());
+ }
+
+ /**
+ * different order does not require the global tag
+ */
+ public void testTag3() {
+ DataSource base = new DataSource();
+ JDBCDataSource baseJDBC = new JDBCDataSource();
+ baseJDBC.setParent(base);
+
+ ArrayList<DataSource> dataSources = new ArrayList<DataSource>();
+ dataSources.add(baseJDBC);
+ dataSources.add(base);
+
+ DataSources ds = new DataSources();
+ ds.setDataSources(dataSources);
+
+ Yaml yaml = new Yaml();
+ String output = yaml.dumpAsMap(ds);
+
+ String etalon = Util.getLocalResource("javabeans/issue10-3.yaml");
+ assertEquals(etalon.trim(), output.trim());
+ // load
+ Yaml beanLoader = new Yaml();
+ DataSources bean = beanLoader.loadAs(output, DataSources.class);
+ Iterator<DataSource> iter = bean.getDataSources().iterator();
+ assertTrue(iter.next() instanceof JDBCDataSource);
+ assertFalse("Must be DataSource.", iter.next() instanceof JDBCDataSource);
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue10/DataSource.java b/src/test/java/org/yaml/snakeyaml/issues/issue10/DataSource.java
new file mode 100644
index 0000000..3063b9e
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue10/DataSource.java
@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue10;
+
+public class DataSource {
+ String name;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue10/DataSources.java b/src/test/java/org/yaml/snakeyaml/issues/issue10/DataSources.java
new file mode 100644
index 0000000..995e2ca
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue10/DataSources.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue10;
+
+import java.util.List;
+
+public class DataSources {
+ List<DataSource> dataSources;
+
+ public List<DataSource> getDataSources() {
+ return dataSources;
+ }
+
+ public void setDataSources(List<DataSource> dataSources) {
+ this.dataSources = dataSources;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue10/JDBCDataSource.java b/src/test/java/org/yaml/snakeyaml/issues/issue10/JDBCDataSource.java
new file mode 100644
index 0000000..e80193e
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue10/JDBCDataSource.java
@@ -0,0 +1,56 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue10;
+
+public class JDBCDataSource extends DataSource {
+ String username;
+ String password;
+ String url;
+
+ DataSource parent;
+
+ public DataSource getParent() {
+ return parent;
+ }
+
+ public void setParent(DataSource parent) {
+ this.parent = parent;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue100/Data.java b/src/test/java/org/yaml/snakeyaml/issues/issue100/Data.java
new file mode 100644
index 0000000..1596802
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue100/Data.java
@@ -0,0 +1,65 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue100;
+
+public class Data {
+ private String id;
+ private int age;
+
+ public Data() {
+ this.id = null;
+ this.age = 999;
+ }
+
+ public Data(String id, int age) {
+ this.id = id;
+ this.age = age;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public int getAge() {
+ return age;
+ }
+
+ public void setAge(int age) {
+ this.age = age;
+ }
+
+ @Override
+ public String toString() {
+ return "Data [age=" + age + ", id=" + id + "]";
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof Data) {
+ return toString().equals(obj.toString());
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return toString().hashCode();
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue100/DataBean.java b/src/test/java/org/yaml/snakeyaml/issues/issue100/DataBean.java
new file mode 100644
index 0000000..cd31171
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue100/DataBean.java
@@ -0,0 +1,47 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue100;
+
+public class DataBean {
+ private String id;
+ private Data data;
+ private DataMore more;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public Data getData() {
+ return data;
+ }
+
+ public void setData(Data data) {
+ this.data = data;
+ }
+
+ public DataMore getMore() {
+ return more;
+ }
+
+ public void setMore(DataMore more) {
+ this.more = more;
+ }
+
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue100/DataMore.java b/src/test/java/org/yaml/snakeyaml/issues/issue100/DataMore.java
new file mode 100644
index 0000000..4d4dff3
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue100/DataMore.java
@@ -0,0 +1,43 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue100;
+
+public class DataMore extends Data {
+ private boolean complete;
+
+ public DataMore() {
+ setId("-1");
+ setAge(-1);
+ }
+
+ public DataMore(String id, int age, boolean complete) {
+ super(id, age);
+ this.complete = complete;
+ }
+
+ public boolean isComplete() {
+ return complete;
+ }
+
+ public void setComplete(boolean complete) {
+ this.complete = complete;
+ }
+
+ @Override
+ public String toString() {
+ return "DataMore [complete=" + complete + ", toString()=" + super.toString() + "]";
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue100/MergeJavaBeanTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue100/MergeJavaBeanTest.java
new file mode 100644
index 0000000..2154557
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue100/MergeJavaBeanTest.java
@@ -0,0 +1,198 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue100;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.Constructor;
+
+public class MergeJavaBeanTest extends TestCase {
+
+ @SuppressWarnings("unchecked")
+ public void testNoMerge() {
+ String input = "- &id001 !!org.yaml.snakeyaml.issues.issue100.Data {age: 11, id: id123}\n- *id001";
+ // System.out.println(input);
+ Yaml yaml = new Yaml();
+ List<Data> list = (List<Data>) yaml.load(input);
+ for (Data data : list) {
+ // System.out.println(data);
+ assertEquals("id123", data.getId());
+ assertEquals(11, data.getAge());
+ }
+ }
+
+ public void testMergeWithTags() {
+ String input = Util.getLocalResource("issues/issue100-1.yaml");
+ // System.out.println(input);
+ Yaml yaml = new Yaml();
+
+ List<?> list = (List<?>) yaml.load(input);
+ // First object: Data ( 11, "id123" )
+ assertEquals(list.get(0).getClass(), Data.class);
+ assertEquals(11, ((Data) list.get(0)).getAge());
+ assertEquals("id123", ((Data) list.get(0)).getId());
+
+ // Second object: Data ( 13, "id456" )
+ assertEquals(list.get(1).getClass(), Data.class);
+ assertEquals(13, ((Data) list.get(1)).getAge());
+ assertEquals("id456", ((Data) list.get(1)).getId());
+
+ // Third object: Data ( 11, "id789" )
+ assertEquals(list.get(2).getClass(), Data.class);
+ assertEquals(11, ((Data) list.get(2)).getAge());
+ assertEquals("id789", ((Data) list.get(2)).getId());
+
+ // 4th object: DataMore ( 30, "id123" )
+ assertEquals(list.get(3).getClass(), DataMore.class);
+ assertEquals(30, ((DataMore) list.get(3)).getAge());
+ assertEquals("id123", ((DataMore) list.get(3)).getId());
+ assertTrue(((DataMore) list.get(3)).isComplete());
+
+ // 5th object: Map ( age: 100 )
+ assertTrue(list.get(4) instanceof Map);
+ assertEquals(1, ((Map<?, ?>) list.get(4)).size());
+ assertTrue(((Map<?, ?>) list.get(4)).containsKey("age"));
+ assertEquals(100, ((Map<?, ?>) list.get(4)).get("age"));
+
+ // 6th object: DataMore ( 100, "id789" )
+ assertEquals(list.get(5).getClass(), DataMore.class);
+ assertEquals(100, ((DataMore) list.get(5)).getAge());
+ assertEquals("id789", ((DataMore) list.get(5)).getId());
+ assertFalse(((DataMore) list.get(5)).isComplete());
+ // All instances except the last Map must be different Data instances
+ Set<Data> dataSet = new HashSet<Data>();
+ for (Object data : list) {
+ if (data instanceof Data) {
+ dataSet.add((Data) data);
+ }
+ }
+ assertEquals("Must be all but one Data instances.", list.size() - 1, dataSet.size());
+ }
+
+ /**
+ * Since to explicit tag is provided JavaBean properties are used to create
+ * a map
+ */
+ @SuppressWarnings("unchecked")
+ public void testMergeBeanToMap() {
+ String input = "- &id001 !!org.yaml.snakeyaml.issues.issue100.Data {age: 11, id: id123}\n- << : *id001";
+ // System.out.println(input);
+ Yaml yaml = new Yaml();
+ List<Object> list = (List<Object>) yaml.load(input);
+ // First object: Data ( 11, "id123" )
+ Data first = (Data) list.get(0);
+ assertEquals(11, first.getAge());
+ assertEquals("id123", first.getId());
+ // Second object is map
+ Map<?, ?> second = (Map<?, ?>) list.get(1);
+ assertEquals(11, second.get("age"));
+ assertEquals("id123", second.get("id"));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testMergeAndDeviate() {
+ String input = "- &id001 !!org.yaml.snakeyaml.issues.issue100.Data {age: 11, id: id123}\n- <<: *id001\n id: id456";
+ // System.out.println(input);
+ Yaml yaml = new Yaml();
+ List<Object> list = (List<Object>) yaml.load(input);
+ // First object: Data ( 11, "id123" )
+ Data first = (Data) list.get(0);
+ assertEquals(11, first.getAge());
+ assertEquals("id123", first.getId());
+ // Second object is map with a diffrent id
+ Map<?, ?> second = (Map<?, ?>) list.get(1);
+ assertEquals(11, second.get("age"));
+ assertEquals("id456", second.get("id"));
+ }
+
+ /**
+ * <pre>
+ * Test that the merge-override works correctly in the case of custom classes / data types.
+ * Two base objects are specified:
+ * id001 refers to Data ( 11, "id123" )
+ * id002 refers to Data ( 37, null ) with a literal null value
+ * The third object is specified as having the properties of id001, with the properties of
+ * id002 overriding where they conflict.
+ * Data ( 37, "id123" )
+ * </pre>
+ */
+ @SuppressWarnings("unchecked")
+ public void testMergeAndDeviateOverride() {
+ String input = "- &id001 !!org.yaml.snakeyaml.issues.issue100.Data {age: 11, id: id123}\n- &id002 !!org.yaml.snakeyaml.issues.issue100.Data {age: 37}\n- <<: [ *id002, *id001 ]";
+ // System.out.println(input);
+ Yaml yaml = new Yaml();
+ List<Data> list = (List<Data>) yaml.load(input);
+
+ // First object: Data ( 11, "id123" )
+ assertEquals(11, list.get(0).getAge());
+ assertEquals("id123", list.get(0).getId());
+
+ // Second object: Data ( 37, null )
+ assertEquals(37, list.get(1).getAge());
+ assertEquals(null, list.get(1).getId());
+
+ // Third object: map
+ Map<?, ?> third = (Map<?, ?>) list.get(2);
+ assertEquals(37, third.get("age"));
+ assertEquals("id123", third.get("id"));
+ }
+
+ /**
+ * When the merged JavaBean is itself a JavaBean property then explicit tag
+ * is not required
+ */
+ public void testMergeBeanProperty() {
+ String input = Util.getLocalResource("issues/issue100-3.yaml");
+ // System.out.println(input);
+ Yaml yaml = new Yaml(new Constructor(DataBean.class));
+ DataBean bean = (DataBean) yaml.load(input);
+ assertEquals("id001", bean.getId());
+ assertEquals("id002", bean.getData().getId());
+ assertEquals(17, bean.getData().getAge());
+ assertEquals(17, bean.getMore().getAge());
+ assertEquals("more003", bean.getMore().getId());
+ assertTrue(bean.getMore().isComplete());
+ }
+
+ /**
+ * Merge map to JavaBean
+ */
+ @SuppressWarnings("unchecked")
+ public void testMergeMapToJavaBean() {
+ String input = "- &id001 { age: 11, id: id123 }\n- !!org.yaml.snakeyaml.issues.issue100.Data\n <<: *id001\n id: id456";
+ // System.out.println(input);
+ Yaml yaml = new Yaml(new Constructor());
+ List<Object> objects = (List<Object>) yaml.load(input);
+ assertEquals(2, objects.size());
+ // Check first type
+ Object first = objects.get(0);
+ Map<Object, Object> firstMap = (Map<Object, Object>) first;
+ // Check first contents
+ assertEquals(11, firstMap.get("age"));
+ assertEquals("id123", firstMap.get("id"));
+ // Check second contents
+ Data secondData = (Data) objects.get(1);
+ assertEquals(11, secondData.getAge());
+ assertEquals("id456", secondData.getId());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue100/MergeMapsTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue100/MergeMapsTest.java
new file mode 100644
index 0000000..c89bc3b
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue100/MergeMapsTest.java
@@ -0,0 +1,42 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue100;
+
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+
+public class MergeMapsTest extends TestCase {
+
+ @SuppressWarnings("unchecked")
+ public void testExplicitMergeTag() {
+ String input = Util.getLocalResource("issues/issue100-2.yaml");
+ // System.out.println(input);
+ Yaml yaml = new Yaml();
+ Map<String, ?> list = (Map<String, ?>) yaml.load(input);
+ List<Map<?, ?>> result = (List<Map<?, ?>>) list.get("result");
+ Map<?, ?> first = result.iterator().next();
+ for (Map<?, ?> data : result) {
+ // System.out.println(data);
+ assertEquals("Size must coinside.", first.size(), data.size());
+ assertEquals(first, data);
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue102/BigDataLoadTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue102/BigDataLoadTest.java
new file mode 100644
index 0000000..7e4beca
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue102/BigDataLoadTest.java
@@ -0,0 +1,75 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue102;
+
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+
+public class BigDataLoadTest extends TestCase {
+ private static final int SIZE = 5000;
+
+ public void testBigStringData() {
+ Yaml yaml = new Yaml();
+ List<?> loaded = (List<?>) yaml.load(getLongYamlDocument(SIZE));
+ assertEquals(SIZE, loaded.size());
+ }
+
+ public void testBigStreamData() {
+ Yaml yaml = new Yaml();
+ StringReader buffer = new StringReader(getLongYamlDocument(SIZE));
+ List<?> loaded = (List<?>) yaml.load(buffer);
+ assertEquals(SIZE, loaded.size());
+ }
+
+ private String getLongYamlDocument(int size) {
+ List<DataBean> beans = new ArrayList<DataBean>();
+ Yaml yaml = new Yaml();
+ StringBuilder builder = new StringBuilder();
+ for (int i = 0; i < size; i++) {
+ List<String> list = new ArrayList<String>();
+ for (int j = 0; j < 10; j++) {
+ list.add(String.valueOf(i + j));
+ }
+ Map<String, Integer> map = new HashMap<String, Integer>();
+ for (int j = 0; j < 10; j++) {
+ map.put(String.valueOf(j), i + j);
+ }
+ DataBean bean = new DataBean();
+ bean.setId("id" + i);
+ bean.setList(list);
+ bean.setMap(map);
+ beans.add(bean);
+ String ooo = yaml.dumpAsMap(bean);
+ String[] lines = ooo.split("\n");
+ builder.append("-\n");
+ for (int j = 0; j < lines.length; j++) {
+ builder.append(" ");
+ builder.append(lines[j]);
+ builder.append("\n");
+ }
+ }
+ String data = builder.toString();
+ System.out.println("Long data size: " + data.length() / 1024 + " kBytes.");
+ return data;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue102/DataBean.java b/src/test/java/org/yaml/snakeyaml/issues/issue102/DataBean.java
new file mode 100644
index 0000000..9b1eb38
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue102/DataBean.java
@@ -0,0 +1,49 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue102;
+
+import java.util.List;
+import java.util.Map;
+
+public class DataBean {
+ private String id;
+ private List<String> list;
+ private Map<String, Integer> map;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public List<String> getList() {
+ return list;
+ }
+
+ public void setList(List<String> list) {
+ this.list = list;
+ }
+
+ public Map<String, Integer> getMap() {
+ return map;
+ }
+
+ public void setMap(Map<String, Integer> map) {
+ this.map = map;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue103/FakeMap.java b/src/test/java/org/yaml/snakeyaml/issues/issue103/FakeMap.java
new file mode 100644
index 0000000..bdced75
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue103/FakeMap.java
@@ -0,0 +1,128 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue103;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Implements map interface, but behaves like collection. It just collects
+ * whatever you put(...) in here. Needed to track duplications in merge
+ * procedure.
+ *
+ * issue100 & issue103
+ */
+public class FakeMap<K, V> implements Map<K, V> {
+
+ class FakeEntry implements java.util.Map.Entry<K, V> {
+
+ private final K key;
+ private V val;
+
+ public FakeEntry(K key, V val) {
+ this.key = key;
+ this.val = val;
+ }
+
+ public K getKey() {
+ return key;
+ }
+
+ public V getValue() {
+ return val;
+ }
+
+ public V setValue(V newV) {
+ V old = val;
+ val = newV;
+ return old;
+ }
+
+ }
+
+ ArrayList<java.util.Map.Entry<K, V>> entries = new ArrayList<Map.Entry<K, V>>();
+
+ public void clear() {
+ entries.clear();
+ }
+
+ public boolean containsKey(Object arg0) {
+ for (java.util.Map.Entry<K, V> entry : entries) {
+ if (entry.getKey().equals(arg0))
+ return true;
+ }
+ return false;
+ }
+
+ public boolean containsValue(Object arg0) {
+ for (java.util.Map.Entry<K, V> entry : entries) {
+ if (entry.getValue().equals(arg0))
+ return true;
+ }
+ return false;
+ }
+
+ public Set<java.util.Map.Entry<K, V>> entrySet() {
+ throw new UnsupportedOperationException();
+ }
+
+ public V get(Object arg0) {
+ for (java.util.Map.Entry<K, V> entry : entries) {
+ if (entry.getKey().equals(arg0))
+ return entry.getValue();
+ }
+ return null;
+ }
+
+ public boolean isEmpty() {
+ return values().isEmpty();
+ }
+
+ public Set<K> keySet() {
+ throw new UnsupportedOperationException();
+ }
+
+ public V put(K key, V val) {
+ entries.add(new FakeEntry(key, val));
+ return null;
+ }
+
+ public void putAll(Map<? extends K, ? extends V> arg0) {
+ throw new UnsupportedOperationException();
+ }
+
+ public V remove(Object arg0) {
+ for (Iterator<java.util.Map.Entry<K, V>> iter = entries.iterator(); iter.hasNext();) {
+ java.util.Map.Entry<K, V> entry = iter.next();
+ if (entry.getKey().equals(arg0)) {
+ iter.remove();
+ return entry.getValue();
+ }
+ }
+ return null;
+ }
+
+ public int size() {
+ return entries.size();
+ }
+
+ public Collection<V> values() {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue103/MergingTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue103/MergingTest.java
new file mode 100644
index 0000000..b825e28
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue103/MergingTest.java
@@ -0,0 +1,120 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue103;
+
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.Constructor;
+
+public class MergingTest extends TestCase {
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ public void testMergeWithDefaultMap() {
+ String input = Util.getLocalResource("issues/issue103.yaml");
+ // System.out.println(input);
+ Yaml yaml = new Yaml();
+
+ check((Map) yaml.load(input));
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ public void testMergeWithFakeMap() {
+ String input = Util.getLocalResource("issues/issue103.yaml");
+ // System.out.println(input);
+ Constructor c = new Constructor() {
+ protected java.util.Map<Object, Object> createDefaultMap() {
+ return new FakeMap<Object, Object>();
+ }
+ };
+
+ Yaml yaml = new Yaml(c);
+
+ check((FakeMap) yaml.load(input));
+ }
+
+ private void check(Map<String, List<Map<Object, Object>>> map) {
+
+ assertEquals(2, map.size());
+ assertTrue(map.containsKey("input"));
+ assertTrue(map.containsKey("result"));
+
+ // input: ...
+ List<Map<Object, Object>> inputList = map.get("input");
+ assertEquals(4, inputList.size());
+
+ Map<Object, Object> center = inputList.get(0);
+ assertEquals(2, center.size());
+ assertEquals(Integer.valueOf(1), center.get("x"));
+ assertEquals(Integer.valueOf(2), center.get("y"));
+
+ Map<Object, Object> left = inputList.get(1);
+ assertEquals(2, left.size());
+ assertEquals(Integer.valueOf(0), left.get("x"));
+ assertEquals(Integer.valueOf(2), left.get("y"));
+
+ Map<Object, Object> big = inputList.get(2);
+ assertEquals(1, big.size());
+ assertEquals(Integer.valueOf(10), big.get("r"));
+
+ Map<Object, Object> small = inputList.get(3);
+ assertEquals(1, small.size());
+ assertEquals(Integer.valueOf(1), small.get("r"));
+
+ // result : ...
+ List<Map<Object, Object>> resultList = map.get("result");
+ assertEquals(5, resultList.size());
+
+ Map<Object, Object> explicitKeys = resultList.get(0);
+ assertEquals(4, explicitKeys.size());
+ assertEquals(Integer.valueOf(1), explicitKeys.get("x"));
+ assertEquals(Integer.valueOf(2), explicitKeys.get("y"));
+ assertEquals(Integer.valueOf(10), explicitKeys.get("r"));
+ assertEquals("center/big", explicitKeys.get("label"));
+
+ Map<?, ?> merge_center = resultList.get(1);
+ assertEquals(4, merge_center.size());
+ assertEquals(Integer.valueOf(1), merge_center.get("x"));
+ assertEquals(Integer.valueOf(2), merge_center.get("y"));
+ assertEquals(Integer.valueOf(10), merge_center.get("r"));
+ assertEquals("center/big", merge_center.get("label"));
+
+ Map<?, ?> merge_left_override = resultList.get(2);
+ assertEquals(4, merge_left_override.size());
+ assertEquals(Integer.valueOf(0), merge_left_override.get("x"));
+ assertEquals(Integer.valueOf(5), merge_left_override.get("y"));
+ assertEquals(Integer.valueOf(10), merge_left_override.get("r"));
+ assertEquals("center/big", merge_left_override.get("label"));
+
+ Map<?, ?> merge_center_big = resultList.get(3);
+ assertEquals(4, merge_center_big.size());
+ assertEquals(Integer.valueOf(1), merge_center_big.get("x"));
+ assertEquals(Integer.valueOf(2), merge_center_big.get("y"));
+ assertEquals(Integer.valueOf(10), merge_center_big.get("r"));
+ assertEquals("center/big", merge_center_big.get("label"));
+
+ Map<?, ?> merge_big_left_small_override = resultList.get(4);
+ assertEquals(4, merge_big_left_small_override.size());
+ assertEquals(Integer.valueOf(1), merge_big_left_small_override.get("x"));
+ assertEquals(Integer.valueOf(2), merge_big_left_small_override.get("y"));
+ assertEquals(Integer.valueOf(10), merge_big_left_small_override.get("r"));
+ assertEquals("center/big", merge_big_left_small_override.get("label"));
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue11/YamlMapTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue11/YamlMapTest.java
new file mode 100644
index 0000000..6550875
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue11/YamlMapTest.java
@@ -0,0 +1,145 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue11;
+
+import java.util.Map;
+import java.util.TreeMap;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.AbstractConstruct;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.ScalarNode;
+import org.yaml.snakeyaml.nodes.Tag;
+import org.yaml.snakeyaml.representer.Represent;
+import org.yaml.snakeyaml.representer.Representer;
+
+public class YamlMapTest extends TestCase {
+ public void testYaml() {
+ Yaml yaml = new Yaml(new ExtendedConstructor(), new ExtendedRepresenter());
+ String output = yaml.dump(new Custom(123));
+ // System.out.println(output);
+ Custom o = (Custom) yaml.load(output);
+ assertEquals("123", o.getStr());
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testYamlMap() {
+ Map<String, Object> data = new TreeMap<String, Object>();
+ data.put("customTag", new Custom(123));
+
+ Yaml yaml = new Yaml(new ExtendedConstructor(), new ExtendedRepresenter());
+ String output = yaml.dump(data);
+ // System.out.println(output);
+ Object o = yaml.load(output);
+
+ assertTrue(o instanceof Map);
+ Map<String, Object> m = (Map<String, Object>) o;
+ assertTrue(m.get("customTag") instanceof Custom);
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testYamlMapBean() {
+ Map<String, Object> data = new TreeMap<String, Object>();
+ data.put("knownClass", new Wrapper("test", new Custom(456)));
+
+ Yaml yaml = new Yaml(new ExtendedConstructor(), new ExtendedRepresenter());
+ String output = yaml.dump(data);
+ // System.out.println(output);
+ Object o = yaml.load(output);
+
+ assertTrue(o instanceof Map);
+ Map<String, Object> m = (Map<String, Object>) o;
+ assertEquals(Wrapper.class, m.get("knownClass").getClass());
+ }
+
+ public static class Wrapper {
+ private String a;
+ private Custom b;
+
+ public Wrapper(String s, Custom bb) {
+ a = s;
+ b = bb;
+ }
+
+ public Wrapper() {
+ }
+
+ public String getA() {
+ return a;
+ }
+
+ public void setA(String s) {
+ a = s;
+ }
+
+ public Custom getB() {
+ return b;
+ }
+
+ public void setB(Custom bb) {
+ b = bb;
+ }
+ }
+
+ public static class Custom {
+ final private String str;
+
+ public Custom(Integer i) {
+ str = i.toString();
+ }
+
+ public Custom(Custom c) {
+ str = c.str;
+ }
+
+ public String toString() {
+ return str;
+ }
+
+ public String getStr() {
+ return str;
+ }
+ }
+
+ public static class ExtendedRepresenter extends Representer {
+ public ExtendedRepresenter() {
+ this.representers.put(Custom.class, new RepresentCustom());
+ }
+
+ private class RepresentCustom implements Represent {
+ public Node representData(Object data) {
+ return representScalar(new Tag("!Custom"), ((Custom) data).toString());
+ }
+ }
+ }
+
+ public static class ExtendedConstructor extends Constructor {
+ public ExtendedConstructor() {
+ this.yamlConstructors.put(new Tag("!Custom"), new ConstructCustom());
+ }
+
+ private class ConstructCustom extends AbstractConstruct {
+ public Object construct(Node node) {
+ String str = (String) constructScalar((ScalarNode) node);
+ return new Custom(new Integer(str));
+ }
+
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue111/LongUriTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue111/LongUriTest.java
new file mode 100644
index 0000000..acf0091
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue111/LongUriTest.java
@@ -0,0 +1,50 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue111;
+
+import java.io.StringReader;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.ScalarNode;
+
+public class LongUriTest extends TestCase {
+ /**
+ * Try loading a tag with a very long escaped URI section (over 256 bytes'
+ * worth).
+ */
+ public void testLongURIEscape() {
+ Yaml loader = new Yaml();
+ // Create a long escaped string by exponential growth...
+ String longEscURI = "%41"; // capital A...
+ for (int i = 0; i < 10; ++i) {
+ longEscURI = longEscURI + longEscURI;
+ }
+ assertEquals(1024 * 3, longEscURI.length());
+ String yaml = "!" + longEscURI + " www";
+
+ Node node = loader.compose(new StringReader(yaml));
+ ScalarNode scalar = (ScalarNode) node;
+ String etalon = "!";
+ for (int i = 0; i < 1024; i++) {
+ etalon += "A";
+ }
+ assertEquals(1025, etalon.length());
+ assertEquals(etalon, scalar.getTag().toString());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue112/MyClass.java b/src/test/java/org/yaml/snakeyaml/issues/issue112/MyClass.java
new file mode 100644
index 0000000..2f7c1b6
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue112/MyClass.java
@@ -0,0 +1,33 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue112;
+
+public class MyClass<T extends Object> {
+ T name;
+
+ public void setName(T name) {
+ this.name = name;
+ }
+
+ public T getName() {
+ return this.name;
+ }
+
+ @Override
+ public String toString() {
+ return name.toString();
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue112/MyCompositeObject.java b/src/test/java/org/yaml/snakeyaml/issues/issue112/MyCompositeObject.java
new file mode 100644
index 0000000..471e678
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue112/MyCompositeObject.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue112;
+
+import java.util.Collection;
+
+public class MyCompositeObject {
+ Collection<MyClass<? extends Object>> things;
+
+ public Collection<MyClass<? extends Object>> getThings() {
+ return this.things;
+ }
+
+ public void setThings(Collection<MyClass<? extends Object>> things) {
+ this.things = things;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue112/ParameterisedTypeLoadingTestCase.java b/src/test/java/org/yaml/snakeyaml/issues/issue112/ParameterisedTypeLoadingTestCase.java
new file mode 100644
index 0000000..6b7f94a
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue112/ParameterisedTypeLoadingTestCase.java
@@ -0,0 +1,65 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue112;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.junit.Test;
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.Constructor;
+
+public class ParameterisedTypeLoadingTestCase {
+
+ @Test
+ public void testParameterisedTypeLoading() throws IOException {
+ Yaml yamlParser = new Yaml(new Constructor(MyCompositeObject.class));
+ MyCompositeObject obj = (MyCompositeObject) yamlParser.load(getInput());
+ check(obj);
+
+ // dump the object
+ Yaml yaml = new Yaml();
+ String output = yaml.dumpAsMap(obj);
+ assertEquals(Util.getLocalResource("issues/issue112-2.yaml"), output);
+ }
+
+ @Test
+ public void testJavaBeanLoader() throws IOException {
+ Yaml yamlParser = new Yaml();
+ MyCompositeObject obj = yamlParser.loadAs(getInput(), MyCompositeObject.class);
+ check(obj);
+ }
+
+ private void check(MyCompositeObject obj) {
+ Object[] values = { 1, "two", 3, "four", "!!!" };
+ assertNotNull(obj);
+ assertEquals(5, obj.getThings().size());
+ int i = 0;
+ for (MyClass<? extends Object> thing : obj.getThings()) {
+ assertEquals(MyClass.class, thing.getClass());
+ assertNotNull("The 'name' property must be set.", thing.getName());
+ assertEquals(values[i++], thing.getName());
+ }
+ }
+
+ private InputStream getInput() throws IOException {
+ return this.getClass().getClassLoader().getResource("issues/issue112-1.yaml").openStream();
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue114/PreserveTypeTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue114/PreserveTypeTest.java
new file mode 100644
index 0000000..fd69f9a
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue114/PreserveTypeTest.java
@@ -0,0 +1,90 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue114;
+
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+
+public class PreserveTypeTest extends TestCase {
+
+ public static class MyBean {
+
+ private int dummy;
+
+ public int getDummy() {
+ return dummy;
+ }
+
+ public void setDummy(int dummy) {
+ this.dummy = dummy;
+ }
+ }
+
+ public static class ReferencingBean {
+
+ private List<MyBean> myBeans = new LinkedList<PreserveTypeTest.MyBean>();
+
+ public List<MyBean> getMyBeans() {
+ return myBeans;
+ }
+
+ public void setMyBeans(List<MyBean> myBeans) {
+ this.myBeans = myBeans;
+ }
+ }
+
+ private Map<String, Object> createData(boolean collectionFirst) {
+ MyBean myBean = new MyBean();
+ ReferencingBean referencingBean = new ReferencingBean();
+ referencingBean.getMyBeans().add(myBean);
+
+ LinkedHashMap<String, Object> map = new LinkedHashMap<String, Object>();
+ if (collectionFirst) {
+ map.put("referencingBean", referencingBean);
+ map.put("myBean", myBean);
+ } else {
+ map.put("myBean", myBean);
+ map.put("referencingBean", referencingBean);
+ }
+ return map;
+ }
+
+ private void check(String doc) {
+ Yaml yaml = new Yaml();
+ @SuppressWarnings("unchecked")
+ Map<String, Object> loaded = (Map<String, Object>) yaml.load(doc);
+ Object myBean2 = loaded.get("myBean");
+ assertTrue(myBean2.getClass().toString(), myBean2 instanceof MyBean);
+ }
+
+ public void testPreserveType1() {
+ Yaml yaml = new Yaml();
+ String s = yaml.dump(createData(true));
+ check(s);
+ }
+
+ public void testPreserveType2() {
+ Yaml yaml = new Yaml();
+ String s = yaml.dump(createData(false));
+ check(s);
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue115/IssueBean.java b/src/test/java/org/yaml/snakeyaml/issues/issue115/IssueBean.java
new file mode 100644
index 0000000..572b94c
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue115/IssueBean.java
@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue115;
+
+public class IssueBean {
+ private ParameterizedBean<Integer, String> bean = new ParameterizedBean<Integer, String>();
+
+ public ParameterizedBean<Integer, String> getBean() {
+ return bean;
+ }
+
+ public void setBean(ParameterizedBean<Integer, String> bean) {
+ this.bean = bean;
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue115/ParameterizedBean.java b/src/test/java/org/yaml/snakeyaml/issues/issue115/ParameterizedBean.java
new file mode 100644
index 0000000..ad3376a
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue115/ParameterizedBean.java
@@ -0,0 +1,37 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue115;
+
+public class ParameterizedBean<K, V> {
+ private K k;
+ private V v;
+
+ public K getK() {
+ return k;
+ }
+
+ public void setK(K k) {
+ this.k = k;
+ }
+
+ public V getV() {
+ return v;
+ }
+
+ public void setV(V v) {
+ this.v = v;
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue115/ParameterizedJavaBeanTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue115/ParameterizedJavaBeanTest.java
new file mode 100644
index 0000000..ca3ccb4
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue115/ParameterizedJavaBeanTest.java
@@ -0,0 +1,55 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue115;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+
+public class ParameterizedJavaBeanTest extends TestCase {
+
+ public void testAsStandalone() {
+ ParameterizedBean<Integer, String> bean = new ParameterizedBean<Integer, String>();
+ bean.setK(13);
+ bean.setV("ID47");
+ Yaml yaml = new Yaml();
+ String result = yaml.dump(bean);
+ assertEquals("!!org.yaml.snakeyaml.issues.issue115.ParameterizedBean {k: 13, v: ID47}\n",
+ result);
+ // load
+ @SuppressWarnings("unchecked")
+ ParameterizedBean<Integer, String> beanParsed = (ParameterizedBean<Integer, String>) yaml
+ .load(result);
+ assertEquals(new Integer(13), beanParsed.getK());
+ assertEquals("ID47", beanParsed.getV());
+ }
+
+ public void testAsJavaBeanProperty() {
+ Yaml yaml = new Yaml();
+ IssueBean issue = new IssueBean();
+ ParameterizedBean<Integer, String> bean = new ParameterizedBean<Integer, String>();
+ bean.setK(432);
+ bean.setV("Val432");
+ issue.setBean(bean);
+ String result = yaml.dump(issue);
+ assertEquals("!!org.yaml.snakeyaml.issues.issue115.IssueBean\nbean: {k: 432, v: Val432}\n",
+ result);
+ // load
+ IssueBean issueParsed = (IssueBean) yaml.load(result);
+ assertEquals(new Integer(432), issueParsed.getBean().getK());
+ assertEquals("Val432", issueParsed.getBean().getV());
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue115/ParameterizedTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue115/ParameterizedTest.java
new file mode 100644
index 0000000..c6c69d3
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue115/ParameterizedTest.java
@@ -0,0 +1,56 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue115;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+
+public class ParameterizedTest extends TestCase {
+
+ public void testAsStandalone() {
+ Parameterized<Integer> parm = new Parameterized<Integer>();
+ parm.t = 3;
+ Yaml yaml = new Yaml();
+ String result = yaml.dump(parm);
+ assertEquals("!!org.yaml.snakeyaml.issues.issue115.Parameterized {t: 3}\n", result);
+ @SuppressWarnings("unchecked")
+ // load
+ Parameterized<Integer> parmParsed = (Parameterized<Integer>) yaml.load(result);
+ assertEquals(new Integer(3), parmParsed.t);
+ }
+
+ public void testAsJavaBeanProperty() {
+ Yaml yaml = new Yaml();
+ Issue issue = new Issue();
+ Parameterized<Integer> parm = new Parameterized<Integer>();
+ parm.t = 555;
+ issue.parm = parm;
+ String result = yaml.dump(issue);
+ assertEquals("!!org.yaml.snakeyaml.issues.issue115.Issue\nparm: {t: 555}\n", result);
+ // load
+ Issue issueParsed = (Issue) yaml.load(result);
+ assertEquals(new Integer(555), issueParsed.parm.t);
+ }
+}
+
+class Issue {
+ public Parameterized<Integer> parm = new Parameterized<Integer>();
+}
+
+class Parameterized<T> {
+ public T t;
+}
\ No newline at end of file
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue116/HiddenSpecial.java b/src/test/java/org/yaml/snakeyaml/issues/issue116/HiddenSpecial.java
new file mode 100644
index 0000000..8fea9ff
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue116/HiddenSpecial.java
@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue116;
+
+public class HiddenSpecial {
+ private int inaccessableField;
+
+ public HiddenSpecial(String something) {
+ this.inaccessableField = something.hashCode();
+ }
+
+ public int retrieveMyVerySpecialField() {
+ return inaccessableField;
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue116/NoFieldsTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue116/NoFieldsTest.java
new file mode 100644
index 0000000..044cdb8
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue116/NoFieldsTest.java
@@ -0,0 +1,70 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue116;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.error.YAMLException;
+
+public class NoFieldsTest extends TestCase {
+
+ public void testEmptyClass() {
+ Empty empty = new Empty();
+ Yaml yaml = new Yaml();
+ String result = yaml.dump(empty);
+ assertEquals("!!org.yaml.snakeyaml.issues.issue116.Empty {}\n", result);
+ Object emptyParsed = yaml.load(result);
+ assertTrue(emptyParsed instanceof Empty);
+ }
+
+ public void testHiddenParameter() {
+ Hidden hidden = new Hidden();
+ Yaml yaml = new Yaml();
+ try {
+ yaml.dump(hidden);
+ fail("an exception should have been thrown");
+ } catch (YAMLException e) {
+ assertEquals(e.getMessage(),
+ "No JavaBean properties found in org.yaml.snakeyaml.issues.issue116.Hidden");
+ }
+ Object hiddenParsed = yaml.load("!!org.yaml.snakeyaml.issues.issue116.Hidden {}\n");
+ assertTrue(hiddenParsed instanceof Hidden);
+ }
+
+ public void testSpecialHiddenParameter() {
+ HiddenSpecial hidden = new HiddenSpecial("qwerty");
+ Yaml yaml = new Yaml();
+ try {
+ yaml.dump(hidden);
+ fail("an exception should have been thrown");
+ } catch (YAMLException e) {
+ assertEquals(e.getMessage(),
+ "No JavaBean properties found in org.yaml.snakeyaml.issues.issue116.HiddenSpecial");
+ }
+ HiddenSpecial hs = (HiddenSpecial) yaml
+ .load("!!org.yaml.snakeyaml.issues.issue116.HiddenSpecial foo\n");
+ assertEquals("foo".hashCode(), hs.retrieveMyVerySpecialField());
+ }
+}
+
+class Empty {
+}
+
+class Hidden {
+ @SuppressWarnings("unused")
+ private int inaccessableField;
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue124/Bean124.java b/src/test/java/org/yaml/snakeyaml/issues/issue124/Bean124.java
new file mode 100644
index 0000000..202e84e
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue124/Bean124.java
@@ -0,0 +1,54 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue124;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Bean124 {
+ private String a;
+ private List<Integer> numbers;
+
+ public Bean124() {
+ this.a = "aaa";
+ this.numbers = new ArrayList<Integer>(3);
+ numbers.add(1);
+ numbers.add(2);
+ numbers.add(3);
+ }
+
+ public Bean124(String a, List<Integer> numbers) {
+ super();
+ this.a = a;
+ this.numbers = numbers;
+ }
+
+ public String getA() {
+ return a;
+ }
+
+ public void setA(String a) {
+ this.a = a;
+ }
+
+ public List<Integer> getNumbers() {
+ return numbers;
+ }
+
+ public void setNumbers(List<Integer> numbers) {
+ this.numbers = numbers;
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue124/DumpTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue124/DumpTest.java
new file mode 100644
index 0000000..7da5038
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue124/DumpTest.java
@@ -0,0 +1,87 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue124;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.DumperOptions.FlowStyle;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.nodes.Tag;
+
+public class DumpTest extends TestCase {
+
+ public void testDumperOptionsSideEffect() {
+ Yaml yaml = new Yaml();
+ Bean124 bean = new Bean124();
+ String output0 = yaml.dump(bean);
+ // System.out.println(output0);
+ assertEquals("!!org.yaml.snakeyaml.issues.issue124.Bean124\na: aaa\nnumbers: [1, 2, 3]\n",
+ output0);
+ String output1 = yaml.dumpAsMap(bean);
+ // System.out.println(output1);
+ assertEquals("a: aaa\nnumbers:\n- 1\n- 2\n- 3\n", output1);
+ String output2 = yaml.dump(bean);
+ // System.out.println(output2);
+ assertEquals("Yaml.dumpAs() should not have any side effects.", output0, output2);
+ }
+
+ public void testDumperDifferentTag() {
+ Yaml yaml = new Yaml();
+ Bean124 bean = new Bean124();
+ String output1 = yaml.dumpAs(bean, new Tag("!!foo.bar"), FlowStyle.BLOCK);
+ assertEquals("!!foo.bar\na: aaa\nnumbers:\n- 1\n- 2\n- 3\n", output1);
+ }
+
+ public void testDumperFlowStyle() {
+ Yaml yaml = new Yaml();
+ Bean124 bean = new Bean124();
+ String output1 = yaml.dumpAs(bean, new Tag("!!foo.bar"), FlowStyle.FLOW);
+ assertEquals("!!foo.bar {a: aaa, numbers: [1, 2, 3]}\n", output1);
+ }
+
+ public void testDumperAutoStyle() {
+ Yaml yaml = new Yaml();
+ Bean124 bean = new Bean124();
+ String output1 = yaml.dumpAs(bean, new Tag("!!foo.bar"), FlowStyle.AUTO);
+ assertEquals("!!foo.bar\na: aaa\nnumbers: [1, 2, 3]\n", output1);
+ }
+
+ public void testDumperNullStyle() {
+ Yaml yaml = new Yaml();
+ Bean124 bean = new Bean124();
+ String output1 = yaml.dumpAs(bean, new Tag("!!foo.bar"), null);
+ assertEquals("!!foo.bar\na: aaa\nnumbers: [1, 2, 3]\n", output1);
+ }
+
+ public void testDumperNullStyle2() {
+ DumperOptions options = new DumperOptions();
+ options.setDefaultFlowStyle(FlowStyle.BLOCK);
+ Yaml yaml = new Yaml(options);
+ Bean124 bean = new Bean124();
+ String output1 = yaml.dumpAs(bean, new Tag("!!foo2.bar2"), null);
+ assertEquals("!!foo2.bar2\na: aaa\nnumbers:\n- 1\n- 2\n- 3\n", output1);
+ }
+
+ public void testDumperNullTag() {
+ Yaml yaml = new Yaml();
+ Bean124 bean = new Bean124();
+ String output1 = yaml.dumpAs(bean, null, FlowStyle.BLOCK);
+ assertEquals(
+ "!!org.yaml.snakeyaml.issues.issue124.Bean124\na: aaa\nnumbers:\n- 1\n- 2\n- 3\n",
+ output1);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue127/Bean.java b/src/test/java/org/yaml/snakeyaml/issues/issue127/Bean.java
new file mode 100644
index 0000000..d347249
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue127/Bean.java
@@ -0,0 +1,37 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue127;
+
+public class Bean {
+ private String a;
+ private String b;
+
+ public String getA() {
+ return a;
+ }
+
+ public void setA(String a) {
+ this.a = a;
+ }
+
+ public String getB() {
+ return b;
+ }
+
+ public void setB(String b) {
+ this.b = b;
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue127/NullAliasTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue127/NullAliasTest.java
new file mode 100644
index 0000000..bd3da2f
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue127/NullAliasTest.java
@@ -0,0 +1,56 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue127;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.Tag;
+import org.yaml.snakeyaml.representer.Represent;
+import org.yaml.snakeyaml.representer.Representer;
+
+public class NullAliasTest extends TestCase {
+ private static final Tag MY_TAG = new Tag("tag:example.com,2011:bean");
+
+ public void testRespresenter() {
+ Bean bean = new Bean();
+
+ bean.setA("a"); // leave b null
+ Yaml yaml = new Yaml(new BeanRepresenter());
+ String output = yaml.dump(bean);
+ assertEquals("!<tag:example.com,2011:bean>\na: a\nb: null\n", output);
+ }
+
+ class BeanRepresenter extends Representer {
+ public BeanRepresenter() {
+ this.representers.put(Bean.class, new RepresentBean());
+ }
+
+ private class RepresentBean implements Represent {
+ public Node representData(Object data) {
+ Bean bean = (Bean) data;
+ Map<String, Object> fields = new LinkedHashMap<String, Object>(2);
+ fields.put("a", bean.getA());
+ fields.put("b", bean.getB());
+ return representMapping(MY_TAG, fields, false);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue132/ScalarEventTagTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue132/ScalarEventTagTest.java
new file mode 100644
index 0000000..52eb0bd
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue132/ScalarEventTagTest.java
@@ -0,0 +1,59 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue132;
+
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.events.Event;
+import org.yaml.snakeyaml.events.ScalarEvent;
+import org.yaml.snakeyaml.nodes.Node;
+
+/**
+ * to test http://code.google.com/p/snakeyaml/issues/detail?id=132
+ */
+public class ScalarEventTagTest extends TestCase {
+ public void testLoad() {
+ Yaml yaml = new Yaml();
+ Iterable<Event> parsed = yaml.parse(new StringReader("5"));
+ List<Event> events = new ArrayList<Event>(5);
+ for (Event event : parsed) {
+ events.add(event);
+ // System.out.println(event);
+ }
+ String tag = ((ScalarEvent) events.get(2)).getTag();
+ assertNull("The tag should not be specified: " + tag, tag);
+ }
+
+ public void testDump() {
+ Yaml yaml = new Yaml();
+ Node intNode = yaml.represent(7);
+ assertEquals("tag:yaml.org,2002:int", intNode.getTag().toString());
+ // System.out.println(intNode);
+ List<Event> intEvents = yaml.serialize(intNode);
+ String tag = ((ScalarEvent) intEvents.get(2)).getTag();
+ assertEquals("Without the tag emitter would not know how to emit '7'",
+ "tag:yaml.org,2002:int", tag);
+ //
+ Node strNode = yaml.represent("7");
+ assertEquals("tag:yaml.org,2002:str", strNode.getTag().toString());
+ // System.out.println(strNode);
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue133/StackOverflowTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue133/StackOverflowTest.java
new file mode 100644
index 0000000..080081d
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue133/StackOverflowTest.java
@@ -0,0 +1,72 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue133;
+
+import java.awt.Point;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.introspector.Property;
+import org.yaml.snakeyaml.nodes.NodeTuple;
+import org.yaml.snakeyaml.nodes.Tag;
+import org.yaml.snakeyaml.representer.Representer;
+
+/**
+ * to test http://code.google.com/p/snakeyaml/issues/detail?id=133
+ */
+public class StackOverflowTest extends TestCase {
+ public void testDumpRecursiveObject() {
+ try {
+ Yaml yaml = new Yaml();
+ // by default it must fail with StackOverflow
+ yaml.dump(new Point());
+ fail("getLocation() is recursive.");
+ } catch (Throwable e) {
+ String message = e.getMessage();
+ assertTrue("StackOverflow has no message: " + e.getMessage(), message == null
+ || message.contains("Unable to find getter for property 'location'"));
+ }
+ }
+
+ /**
+ * Since Point.getLocation() creates a new instance of Point class,
+ * SnakeYAML will fail to dump an instance of Point if 'getLocation()' is
+ * also included.
+ *
+ * Since Point is not really a JavaBean, we can safely skip the recursive
+ * property when we dump the instance of Point.
+ */
+ private class PointRepresenter extends Representer {
+
+ @Override
+ protected NodeTuple representJavaBeanProperty(Object javaBean, Property property,
+ Object propertyValue, Tag customTag) {
+ if (javaBean instanceof Point && "location".equals(property.getName())) {
+ return null;
+ } else {
+ return super
+ .representJavaBeanProperty(javaBean, property, propertyValue, customTag);
+ }
+ }
+ }
+
+ public void testDump() {
+ Yaml yaml = new Yaml(new PointRepresenter());
+ String output = yaml.dump(new Point());
+ assertEquals("!!java.awt.Point {x: 0, y: 0}\n", output);
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue136/TabInScalarTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue136/TabInScalarTest.java
new file mode 100644
index 0000000..09c3b08
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue136/TabInScalarTest.java
@@ -0,0 +1,51 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue136;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+
+public class TabInScalarTest extends TestCase {
+
+ public void testTab() {
+ String data = (String) new Yaml().load("L\tD");
+ assertEquals("L\tD", data);
+ }
+
+ public void testNoTab() {
+ String data = (String) new Yaml().load("L D");
+ assertEquals("L D", data);
+ }
+
+ public void testTabDoubleQuotes() {
+ String data = (String) new Yaml().load("\"L\tD\"");
+ // System.out.println(data);
+ assertEquals("L\tD", data);
+ }
+
+ public void testTabSingleQuotes() {
+ String data = (String) new Yaml().load("'L\tD'");
+ // System.out.println(data);
+ assertEquals("L\tD", data);
+ }
+
+ public void testDumpTab() {
+ String data = (String) new Yaml().dump("L\tD");
+ // System.out.println(data);
+ assertEquals("\"L\\tD\"\n", data);
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue137/SupplementaryCharactersTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue137/SupplementaryCharactersTest.java
new file mode 100644
index 0000000..389735d
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue137/SupplementaryCharactersTest.java
@@ -0,0 +1,63 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue137;
+
+import java.io.UnsupportedEncodingException;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+
+/**
+ * http://java.sun.com/developer/technicalArticles/Intl/Supplementary/
+ */
+public class SupplementaryCharactersTest extends TestCase {
+
+ public void testSupplementaryCharacter() {
+ Yaml yaml = new Yaml();
+ String parsed = (String) yaml.load("\"\\U0001f648\"");
+ assertEquals("\ud83d\ude48", parsed);
+ // System.out.println(data);
+ }
+
+ public void testBasicMultilingualPlane() {
+ Yaml yaml = new Yaml();
+ String parsed = (String) yaml.load("\"\\U00000041\"");
+ assertEquals("A", parsed);
+ }
+
+ /**
+ * Supplementary Characters are dumped as binary
+ */
+ public void testDumpSupplementaryCharacter() throws UnsupportedEncodingException {
+ String supplementary = "\ud83d\ude48";
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(supplementary);
+ assertEquals("!!binary |-\n 8J+ZiA==\n", output);
+ byte[] binary = (byte[]) yaml.load(output);
+ String binString = new String(binary, "UTF-8");
+ assertEquals(supplementary, binString);
+ }
+
+ public void testLoadSupplementaryCharacter() {
+ try {
+ new Yaml().load("\"\ud83d\ude48\"\n");
+ fail("Are Supplementary Characters printable ?");
+ } catch (Exception e) {
+ assertEquals("special characters are not allowed", e.getMessage());
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue138/ReaderExceptionTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue138/ReaderExceptionTest.java
new file mode 100644
index 0000000..851ab17
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue138/ReaderExceptionTest.java
@@ -0,0 +1,35 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue138;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.reader.ReaderException;
+
+public class ReaderExceptionTest extends TestCase {
+
+ public void testGetters() {
+ try {
+ new Yaml().load("012\u0019");
+ fail();
+ } catch (ReaderException e) {
+ assertEquals(3, e.getPosition());
+ assertEquals("'string'", e.getName());
+ assertEquals('\u0019', e.getCharacter());
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue139/MergeValueTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue139/MergeValueTest.java
new file mode 100644
index 0000000..debf99f
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue139/MergeValueTest.java
@@ -0,0 +1,70 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue139;
+
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+
+public class MergeValueTest extends TestCase {
+
+ public void testNotUniqueSimple() {
+ String simple = "{key: 1, key: 2}";
+ Yaml yaml = new Yaml();
+ @SuppressWarnings("unchecked")
+ Map<String, Integer> map = (Map<String, Integer>) yaml.load(simple);
+ assertEquals(1, map.size());
+ assertEquals(new Integer(2), map.get("key"));
+ }
+
+ public void testMerge() {
+ check("issues/issue139-1.yaml");// merge with unique keys
+ check("issues/issue139-2.yaml");// merge with same key
+ }
+
+ private void check(String name) {
+ String input = Util.getLocalResource(name);
+ // System.out.println(input);
+ Yaml yaml = new Yaml();
+ @SuppressWarnings("unchecked")
+ Map<String, Object> map = (Map<String, Object>) yaml.load(input);
+ assertEquals(2, map.size());
+ assertTrue(map.containsKey("common"));
+ assertTrue(map.containsKey("production"));
+ assertEquals(map.get("common"), map.get("production"));
+ }
+
+ /**
+ * http://yaml.org/type/merge.html: If the value associated with the key is
+ * a single mapping node, each of its key/value pairs is inserted into the
+ * current mapping, <b>unless the key already exists in it</b>.
+ */
+ @SuppressWarnings("unchecked")
+ public void testMergeUnlessAlreadyExists() {
+ String input = Util.getLocalResource("issues/issue139-3.yaml");
+ // System.out.println(input);
+ Yaml yaml = new Yaml();
+ Map<String, Object> map = (Map<String, Object>) yaml.load(input);
+ assertEquals(2, map.size());
+ Map<String, Integer> common = (Map<String, Integer>) map.get("common");
+ Map<String, Integer> production = (Map<String, Integer>) map.get("production");
+ assertEquals(new Integer(2), common.get("key"));
+ assertEquals(new Integer(3), production.get("key"));
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue139/UniqueKeyTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue139/UniqueKeyTest.java
new file mode 100644
index 0000000..4117b97
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue139/UniqueKeyTest.java
@@ -0,0 +1,64 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue139;
+
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.error.YAMLException;
+import org.yaml.snakeyaml.nodes.MappingNode;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.NodeTuple;
+
+public class UniqueKeyTest extends TestCase {
+
+ public void testNotUnique() {
+ String data = "{key: 1, key: 2}";
+ Yaml yaml = new Yaml(new UniqueKeyConstructor());
+ try {
+ yaml.load(data);
+ fail("The same key must be rejected");
+ } catch (Exception e) {
+ assertEquals("The key is not unique key", e.getMessage());
+ }
+ }
+
+ private class UniqueKeyConstructor extends Constructor {
+
+ @Override
+ protected void constructMapping2ndStep(MappingNode node, Map<Object, Object> mapping) {
+ List<NodeTuple> nodeValue = (List<NodeTuple>) node.getValue();
+ for (NodeTuple tuple : nodeValue) {
+ Node keyNode = tuple.getKeyNode();
+ Node valueNode = tuple.getValueNode();
+ Object key = constructObject(keyNode);
+ if (key != null) {
+ key.hashCode();// check circular dependencies
+ }
+ Object value = constructObject(valueNode);
+ Object old = mapping.put(key, value);
+ if (old != null) {
+ throw new YAMLException("The key is not unique " + key);
+ }
+ }
+ }
+ }
+
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue141/ConfigurableTimezoneTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue141/ConfigurableTimezoneTest.java
new file mode 100644
index 0000000..872af85
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue141/ConfigurableTimezoneTest.java
@@ -0,0 +1,45 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue141;
+
+import java.util.Date;
+import java.util.TimeZone;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Yaml;
+
+public class ConfigurableTimezoneTest extends TestCase {
+
+ public void testNoTimezone() {
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(new Date());
+ assertTrue(output, output.endsWith("Z\n"));
+ }
+
+ public void testTimezone() {
+ DumperOptions options = new DumperOptions();
+ options.setTimeZone(TimeZone.getTimeZone("GMT+1:00"));
+ Yaml yaml = new Yaml(options);
+ Date date = new Date();
+ String output = yaml.dump(date);
+ // System.out.println(output);
+ assertTrue(output, output.trim().endsWith("+1:00"));
+ Date parsed = (Date) yaml.load(output);
+ assertEquals(date, parsed);
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue143/GenericMapTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue143/GenericMapTest.java
new file mode 100644
index 0000000..c98449e
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue143/GenericMapTest.java
@@ -0,0 +1,45 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue143;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Yaml;
+
+public class GenericMapTest extends TestCase {
+
+ public void testMap() throws Exception {
+ BeanWithMap fact = new BeanWithMap();
+ GenericMap<Integer> shash = fact.getMap();
+ shash.put("toto", new Integer(10));
+ DumperOptions options = new DumperOptions();
+ options.setAllowReadOnlyProperties(true);
+ Yaml yaml = new Yaml(options);
+ // String txt = yaml.dump(fact);
+ // assertTrue(txt.contains("org.yaml.snakeyaml.issues.issue143.GenericMapTest"));
+ }
+
+ public static class GenericMap<T> extends java.util.HashMap<String, T> {
+ private static final long serialVersionUID = -6833859369398863926L;
+ }
+
+ public class BeanWithMap {
+ public GenericMap<Integer> getMap() {
+ return new GenericMap<Integer>();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue144/BeanData.java b/src/test/java/org/yaml/snakeyaml/issues/issue144/BeanData.java
new file mode 100644
index 0000000..7988000
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue144/BeanData.java
@@ -0,0 +1,46 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue144;
+
+public class BeanData {
+ private String id;
+ private float number;
+
+ public BeanData() {
+ this.id = "noid";
+ }
+
+ public BeanData(String id) {
+ this.id = id;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public float getNumber() {
+ return number;
+ }
+
+ public void setNumber(float number) {
+ this.number = number;
+ }
+
+}
\ No newline at end of file
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue144/FloatPropertyTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue144/FloatPropertyTest.java
new file mode 100644
index 0000000..b9492aa
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue144/FloatPropertyTest.java
@@ -0,0 +1,42 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue144;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.extensions.compactnotation.CompactConstructor;
+
+public class FloatPropertyTest extends TestCase {
+
+ public void testFloatAsJavaBeanProperty() throws Exception {
+ BeanData bean = new BeanData();
+ bean.setId("id1");
+ bean.setNumber(3.5f);
+ Yaml yaml = new Yaml();
+ String txt = yaml.dump(bean);
+ BeanData parsed = yaml.loadAs(txt, BeanData.class);
+ assertEquals(3.5f, parsed.getNumber());
+ }
+
+ public void testCompact() {
+ Yaml yaml = new Yaml(new CompactConstructor());
+ BeanData obj = (BeanData) yaml
+ .load("org.yaml.snakeyaml.issues.issue144.BeanData(id): { number: 123.4 }");
+ assertEquals(123.4f, obj.getNumber());
+ }
+
+}
\ No newline at end of file
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue145/AbstractThing.java b/src/test/java/org/yaml/snakeyaml/issues/issue145/AbstractThing.java
new file mode 100644
index 0000000..c169e38
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue145/AbstractThing.java
@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue145;
+
+public abstract class AbstractThing {
+ protected String id;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue145/CompleteThing.java b/src/test/java/org/yaml/snakeyaml/issues/issue145/CompleteThing.java
new file mode 100644
index 0000000..eca4a06
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue145/CompleteThing.java
@@ -0,0 +1,24 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue145;
+
+public class CompleteThing extends AbstractThing {
+
+ @Override
+ public String toString() {
+ return "CompleteThing-" + id;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue145/LineNumberInExceptionTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue145/LineNumberInExceptionTest.java
new file mode 100644
index 0000000..39c8c74
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue145/LineNumberInExceptionTest.java
@@ -0,0 +1,55 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue145;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+
+public class LineNumberInExceptionTest extends TestCase {
+
+ public void testLineReport() {
+ Yaml yaml = new Yaml();
+ try {
+ yaml.load("---\n!!org.yaml.snakeyaml.issues.issue145.AbstractThing { id: QQQ }");
+ fail("Instances for abstract classes cannot be created");
+ } catch (Exception e) {
+ assertTrue(e.toString().contains("line 2, column 1"));
+ assertEquals(
+ "Can't construct a java object for tag:yaml.org,2002:org.yaml.snakeyaml.issues.issue145.AbstractThing; exception=java.lang.InstantiationException\n"
+ + " in 'string', line 2, column 1:\n"
+ + " !!org.yaml.snakeyaml.issues.issu ... \n" + " ^\n",
+ e.getMessage());
+ }
+ }
+
+ public void testCompleteThing() {
+ Yaml yaml = new Yaml();
+ CompleteThing thing = (CompleteThing) yaml
+ .load("---\n!!org.yaml.snakeyaml.issues.issue145.CompleteThing { id: QQQ }");
+ assertEquals("QQQ", thing.getId());
+ }
+
+ public void testWrongParameter() {
+ Yaml yaml = new Yaml();
+ try {
+ yaml.load("---\n!!org.yaml.snakeyaml.issues.issue145.CompleteThing { id2: QQQ }");
+ fail("Invalid parameter");
+ } catch (Exception e) {
+ assertTrue("The error should ponit to QQQ.", e.toString().contains("line 2, column 59"));
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue147/PrintableTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue147/PrintableTest.java
new file mode 100644
index 0000000..a534b49
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue147/PrintableTest.java
@@ -0,0 +1,29 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue147;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+
+public class PrintableTest extends TestCase {
+ // http://code.google.com/p/snakeyaml/issues/detail?id=147
+ public void testFFFD() {
+ Yaml yaml = new Yaml();
+ String fffd = (String) yaml.load(yaml.dump("\uFFFD"));
+ assertEquals("\uFFFD", fffd);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue148/PrintableUnicodeTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue148/PrintableUnicodeTest.java
new file mode 100644
index 0000000..0fa9322
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue148/PrintableUnicodeTest.java
@@ -0,0 +1,177 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue148;
+
+import java.util.Formatter;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.DumperOptions.ScalarStyle;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.reader.ReaderException;
+
+public class PrintableUnicodeTest extends TestCase {
+ public void testFFFD() {
+ Yaml yaml = createYaml();
+ String fffd = yaml.dump("\uFFFD");
+ assertEquals("\"\\ufffd\"\n", fffd);
+ }
+
+ public void testSerialization() {
+ // test serialization of all Unicode codepoints
+ Yaml yaml = createYaml();
+ for (int c = Character.MIN_VALUE; c <= Character.MAX_VALUE; c++) {
+ String original = Character.toString((char) c);
+ String serialized = yaml.dump(original);
+
+ // "On output, a YAML processor must only produce these acceptable
+ // characters,
+ // and should also escape all non-printable Unicode characters."
+ for (int i = 0; i < serialized.length(); i++) {
+ int cp = (int) serialized.charAt(i);
+ if (!isAcceptable(cp))
+ fail(String.format(
+ "U+%04x: Serialization produced result with unacceptable U+%04x\n", c,
+ cp));
+ if (!isPrintable(cp))
+ fail(String.format(
+ "U+%04x: Serialization produced result with nonprintable U+%04x\n", c,
+ cp));
+ }
+ }
+ }
+
+ public void testDeserialization() {
+ // test deserialization of non-escaped codepoints
+ for (int c = Character.MIN_VALUE; c <= Character.MAX_VALUE; c++) {
+ // ignore breaks, which have special meaning
+ if (c == 0x0A || c == 0x0D || c == 0x85 || c == 0x2028 || c == 0x2029)
+ continue;
+ if (!isAcceptable(c) || c == 0x27)
+ continue;
+ String expected = Character.toString((char) c);
+ String serialized = "'" + expected + "'";
+
+ String result;
+ try {
+ result = new Yaml().load(serialized).toString();
+ } catch (ReaderException e) {
+ fail(String
+ .format("U+%04x: Deserialization threw ReaderException for an acceptable character\n",
+ c));
+ continue;
+ }
+ if (!result.equals(expected))
+ fail(String.format("U+%04x: Deserialization incorrect: %s\n", c, hexdump(result)));
+ }
+ }
+
+ public void testDeserialization2() {
+ // test deserialization of escaped codepoints
+ // "Any such characters must be presented using escape sequences."
+ for (int c = Character.MIN_VALUE; c <= Character.MAX_VALUE; c++) {
+ String expected = Character.toString((char) c);
+ String serialized = String.format("\"\\u%04x\"", c);
+
+ String result;
+ try {
+ result = new Yaml().load(serialized).toString();
+ } catch (ReaderException e) {
+ fail(String
+ .format("U+%04x: Deserialization threw ReaderException for an acceptable escaped character\n",
+ c));
+ continue;
+ }
+ if (!result.equals(expected))
+ fail(String.format("U+%04x: Deserialization of escaped character incorrect: %s\n",
+ c, hexdump(result)));
+ }
+ }
+
+ private Yaml createYaml() {
+ DumperOptions options = new DumperOptions();
+ options.setAllowUnicode(false);
+ options.setDefaultScalarStyle(ScalarStyle.DOUBLE_QUOTED);
+ return new Yaml(options);
+ }
+
+ /**
+ * Test whether a character is printable, according to the YAML spec.
+ * ('c-printable')
+ */
+ public static boolean isPrintable(int c) {
+ return c == 0x9 || c == 0xA || c == 0xD || (c >= 0x20 && c <= 0x7E) // 8
+ // bit
+ || c == 0x85 || (c >= 0xA0 && c <= 0xD7FF) || (c >= 0xE000 && c <= 0xFFFD) // 16
+ // bit
+ || (c >= 0x10000 && c <= 0x10FFFF); // 32 bit
+ }
+
+ /**
+ * "On input, a YAML processor must accept all printable ASCII characters,
+ * the space, tab, line break, and all Unicode characters beyond #x9F. On
+ * output, a YAML processor must only produce these acceptable characters,
+ * and should also escape all non-printable Unicode characters. The allowed
+ * character range explicitly excludes the surrogate block #xD800-#xDFFF,
+ * DEL #x7F, the C0 control block #x0-#x1F (except for #x9, #xA, and #xD),
+ * the C1 control block #x80-#x9F, #xFFFE, and #xFFFF."
+ */
+ public static boolean isAcceptable(int c) {
+ return (c >= 0x20 && c <= 0x7e // accept all printable ASCII characters,
+ // the space,
+ || c == 0x09 // tab,
+ || c == 0x0A || c == 0x0D || c == 0x85 || c == 0x2028 || c == 0x2029 // line
+ // break,
+ || isUnicodeCharacter(c) && c >= 0x9F // and all Unicode characters
+ // beyond #x9F
+ ) && !( // The allowed character range explicitly excludes
+ c >= 0xD800 && c <= 0xDFFF // the surrogate block #xD800-#xDFFF
+ || c == 0x7f // DEL #x7F,
+ || c <= 0x1F && !(c == 0x09 || c == 0x0A || c == 0x0D) // the
+ // C0
+ // control
+ // block
+ // #x0-#x1F
+ // (except
+ // for
+ // #x9,
+ // #xA,
+ // and
+ // #xD),
+ || c >= 0x80 && c <= 0x9F // the C1 control block
+ // #x80-#x9F,
+ || c == 0xFFFE // #xFFFE,
+ || c == 0xFFFF // and #xFFFF.
+ );
+ }
+
+ /**
+ * Tests whether a codepoint is a designated Unicode noncharacter or not.
+ */
+ public static boolean isUnicodeCharacter(int c) {
+ int plane = c / 0x10000;
+ return !(c >= 0xFDD0 && c <= 0xFDEF) && (plane <= 16 && (c & 0xFFFE) != 0xFFFE);
+ }
+
+ public static String hexdump(String input) {
+ StringBuilder result = new StringBuilder();
+ Formatter formatter = new Formatter(result);
+ for (int i = 0; i < input.length(); i++)
+ formatter.format("%02x ", (int) input.charAt(i));
+ return result.toString();
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue149/ComponentBean.java b/src/test/java/org/yaml/snakeyaml/issues/issue149/ComponentBean.java
new file mode 100644
index 0000000..97f7d1e
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue149/ComponentBean.java
@@ -0,0 +1,37 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue149;
+
+public class ComponentBean {
+ private int property1;
+ private String property2;
+
+ public int getProperty1() {
+ return property1;
+ }
+
+ public void setProperty1(int property1) {
+ this.property1 = property1;
+ }
+
+ public String getProperty2() {
+ return property2;
+ }
+
+ public void setProperty2(String property2) {
+ this.property2 = property2;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue149/GlobalDirectivesTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue149/GlobalDirectivesTest.java
new file mode 100644
index 0000000..6c2b5f4
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue149/GlobalDirectivesTest.java
@@ -0,0 +1,79 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue149;
+
+import java.util.Iterator;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.TypeDescription;
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.nodes.Tag;
+
+public class GlobalDirectivesTest extends TestCase {
+ public void testOneDocument() {
+ String input = Util.getLocalResource("issues/issue149-one-document.yaml");
+ // System.out.println(input);
+ Constructor constr = new Constructor();
+ TypeDescription description = new TypeDescription(ComponentBean.class, new Tag(
+ "tag:ualberta.ca,2012:29"));
+ constr.addTypeDescription(description);
+ Yaml yaml = new Yaml(constr);
+ Iterator<Object> parsed = yaml.loadAll(input).iterator();
+ ComponentBean bean = (ComponentBean) parsed.next();
+ assertEquals(0, bean.getProperty1());
+ assertEquals("aaa", bean.getProperty2());
+ assertFalse(parsed.hasNext());
+ }
+
+ public void testDirectives() {
+ String input = Util.getLocalResource("issues/issue149-losing-directives.yaml");
+ // System.out.println(input);
+ Constructor constr = new Constructor();
+ TypeDescription description = new TypeDescription(ComponentBean.class, new Tag(
+ "tag:ualberta.ca,2012:" + 29));
+ constr.addTypeDescription(description);
+ Yaml yaml = new Yaml(constr);
+ Iterator<Object> parsed = yaml.loadAll(input).iterator();
+ ComponentBean bean1 = (ComponentBean) parsed.next();
+ assertEquals(0, bean1.getProperty1());
+ assertEquals("aaa", bean1.getProperty2());
+ ComponentBean bean2 = (ComponentBean) parsed.next();
+ assertEquals(3, bean2.getProperty1());
+ assertEquals("bbb", bean2.getProperty2());
+ assertFalse(parsed.hasNext());
+ }
+
+ public void testDirectives2() {
+ String input = Util.getLocalResource("issues/issue149-losing-directives-2.yaml");
+ // System.out.println(input);
+ Constructor constr = new Constructor();
+ TypeDescription description = new TypeDescription(ComponentBean.class, new Tag(
+ "tag:ualberta.ca,2012:" + 29));
+ constr.addTypeDescription(description);
+ Yaml yaml = new Yaml(constr);
+ Iterator<Object> parsed = yaml.loadAll(input).iterator();
+ ComponentBean bean1 = (ComponentBean) parsed.next();
+ assertEquals(0, bean1.getProperty1());
+ assertEquals("aaa", bean1.getProperty2());
+ ComponentBean bean2 = (ComponentBean) parsed.next();
+ assertEquals(3, bean2.getProperty1());
+ assertEquals("bbb", bean2.getProperty2());
+ assertFalse(parsed.hasNext());
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue150/Car.java b/src/test/java/org/yaml/snakeyaml/issues/issue150/Car.java
new file mode 100644
index 0000000..1973d9d
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue150/Car.java
@@ -0,0 +1,47 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue150;
+
+import java.util.Collection;
+
+/**
+ *
+ * @author tturki
+ *
+ */
+public class Car {
+ private String plate;
+ private Collection<Wheel> wheels;
+
+ public Car() {
+ }
+
+ public String getPlate() {
+ return plate;
+ }
+
+ public void setPlate(String plate) {
+ this.plate = plate;
+ }
+
+ public Collection<Wheel> getWheels() {
+ return wheels;
+ }
+
+ public void setWheels(Collection<Wheel> wheels) {
+ this.wheels = wheels;
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue150/Wheel.java b/src/test/java/org/yaml/snakeyaml/issues/issue150/Wheel.java
new file mode 100644
index 0000000..bae1637
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue150/Wheel.java
@@ -0,0 +1,31 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue150;
+
+public class Wheel {
+ private Integer id;
+
+ public Wheel() {
+ }
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue150/YamlLoadAsIssueTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue150/YamlLoadAsIssueTest.java
new file mode 100644
index 0000000..f4002d4
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue150/YamlLoadAsIssueTest.java
@@ -0,0 +1,141 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue150;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.AbstractConstruct;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.nodes.MappingNode;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.NodeTuple;
+import org.yaml.snakeyaml.nodes.ScalarNode;
+import org.yaml.snakeyaml.nodes.SequenceNode;
+import org.yaml.snakeyaml.nodes.Tag;
+
+public class YamlLoadAsIssueTest {
+
+ private StringBuilder doc;
+
+ @Before
+ public void setUp() {
+ doc = new StringBuilder();
+ line("!car");
+ line("plate: 12-XP-F4");
+ line("wheels:");
+ line("- w#1");
+ line("- w#2");
+ line("- w#3");
+ line("- w#4");
+ }
+
+ private StringBuilder line(String text) {
+ return doc.append(text).append('\n');
+ }
+
+ @Test
+ public void loadConstructsDocumentCorrectly() {
+ Yaml yaml = yaml();
+ Object result = yaml.load(reader());
+ assertNotNull(result);
+ assertEquals(Car.class, result.getClass());
+ assertEquals("12-XP-F4", ((Car) result).getPlate());
+ assertEquals(4, ((Car) result).getWheels().size());
+ }
+
+ private Yaml yaml() {
+ Yaml yaml = new Yaml(new MyConstructor());
+ yaml.addImplicitResolver(new Tag("!wheel"), Pattern.compile("w#\\d+"), "w");
+ return yaml;
+ }
+
+ @Test
+ public void ignoreImplicitTag() {
+ Yaml yaml = yaml();
+ Car car = yaml.loadAs(reader(), Car.class);
+ assertNotNull(car);
+ assertEquals("12-XP-F4", car.getPlate());
+ ArrayList<Wheel> wheels = new ArrayList<Wheel>(car.getWheels());
+ assertEquals(4, wheels.size());
+ for (int i = 0; i < wheels.size(); i++) {
+ assertEquals(wheels.get(i).getId(), Integer.valueOf(i + 1));
+ }
+ }
+
+ private Reader reader() {
+ return new StringReader(doc.toString());
+ }
+
+ private class MyConstructor extends Constructor {
+ public MyConstructor() {
+ yamlConstructors.put(new Tag("!car"), new ConstructCar());
+ yamlConstructors.put(new Tag("!wheel"), new ConstructWheel());
+ }
+
+ private String toScalarString(Node node) {
+ return (String) constructScalar((ScalarNode) node);
+ }
+
+ private class ConstructCar extends AbstractConstruct {
+
+ @SuppressWarnings("unchecked")
+ public Car construct(Node node) {
+ Car car = new Car();
+ MappingNode mapping = (MappingNode) node;
+ List<NodeTuple> list = mapping.getValue();
+ for (NodeTuple tuple : list) {
+ String field = toScalarString(tuple.getKeyNode());
+ if ("plate".equals(field)) {
+ car.setPlate(toScalarString(tuple.getValueNode()));
+ }
+ if ("wheels".equals(field)) {
+ SequenceNode snode = (SequenceNode) tuple.getValueNode();
+ List<Wheel> wheels = (List<Wheel>) constructSequence(snode);
+ car.setWheels(wheels);
+ }
+ }
+ return car;
+ }
+ }
+
+ private class ConstructWheel extends AbstractConstruct {
+
+ public Wheel construct(Node node) {
+ Wheel w = null;
+ String strValue = toScalarString(node);
+ if (strValue != null && strValue.length() > 2) {
+ strValue = strValue.trim().substring(2);
+ w = new Wheel();
+ w.setId(Integer.valueOf(strValue));
+ }
+ return w;
+ }
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue151/EscapedUnicodeTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue151/EscapedUnicodeTest.java
new file mode 100644
index 0000000..86a88fc
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue151/EscapedUnicodeTest.java
@@ -0,0 +1,36 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue151;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+
+public class EscapedUnicodeTest extends TestCase {
+
+ public void testUnicode() {
+ Yaml yaml = new Yaml();
+ // http://www.tutorialspoint.com/html/ascii_table_lookup.htm
+ String str = (String) yaml.load("\"\\xC3\\xA4\"");
+ assertEquals("2 escape sequences must be converted to 2 characters.", "ä", str);
+ }
+
+ public void testUnicode2() {
+ Yaml yaml = new Yaml();
+ String str = (String) yaml.load("\"Acetylsalicyls\\xE4ure\"");
+ assertEquals("E4 -> ä", "Acetylsalicylsäure", str);
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue154/MissingPropertyTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue154/MissingPropertyTest.java
new file mode 100644
index 0000000..6a4c514
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue154/MissingPropertyTest.java
@@ -0,0 +1,85 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue154;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.error.YAMLException;
+import org.yaml.snakeyaml.representer.Representer;
+
+public class MissingPropertyTest extends TestCase {
+
+ private Yaml yaml;
+
+ public void setUp() {
+ yaml = new Yaml();
+ }
+
+ /**
+ * A normal scalar property should work fine.
+ */
+ public void testPublicField() throws Exception {
+ String doc = "hello: 5";
+ TestBean bean = yaml.loadAs(doc, TestBean.class);
+ assertNotNull(bean);
+ assertEquals(5, bean.hello);
+ }
+
+ /**
+ * By default, unknown fields should throw a YAMLException.
+ */
+ public void testUnknownField() throws Exception {
+ try {
+ String doc = "goodbye: 10";
+ yaml.loadAs(doc, TestBean.class);
+ } catch (YAMLException e) {
+ assertTrue(e.getMessage().contains("Cannot create property=goodbye"));
+ }
+ }
+
+ /**
+ * A new method setSkipMissingProperties(boolean) was added to configure
+ * whether missing properties should throw a YAMLException (the default) or
+ * simply show a warning. The default is false.
+ */
+ public void testSkipMissingProperties() throws Exception {
+ Representer representer = new Representer();
+ representer.getPropertyUtils().setSkipMissingProperties(true);
+ yaml = new Yaml(new Constructor(), representer);
+ String doc = "goodbye: 10\nhello: 5\nfizz: [1]";
+ TestBean bean = yaml.loadAs(doc, TestBean.class);
+ assertNotNull(bean);
+ assertEquals(5, bean.hello);
+ }
+
+ /**
+ * The default for setSkipMissingProperties(boolean) is false; this just
+ * ensures it works if set manually.
+ */
+ public void testNoSkipMissingProperties() throws Exception {
+ try {
+ Representer representer = new Representer();
+ representer.getPropertyUtils().setSkipMissingProperties(false);
+ yaml = new Yaml(new Constructor(), representer);
+ String doc = "goodbye: 10";
+ yaml.loadAs(doc, TestBean.class);
+ } catch (YAMLException e) {
+ assertTrue(e.getMessage().contains("Cannot create property=goodbye"));
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue154/TestBean.java b/src/test/java/org/yaml/snakeyaml/issues/issue154/TestBean.java
new file mode 100644
index 0000000..264b58b
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue154/TestBean.java
@@ -0,0 +1,20 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue154;
+
+public class TestBean {
+ public int hello;
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue155/BinaryTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue155/BinaryTest.java
new file mode 100644
index 0000000..f5c5ef2
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue155/BinaryTest.java
@@ -0,0 +1,34 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue155;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+
+public class BinaryTest extends TestCase {
+
+ public void testBinaryString() throws Exception {
+ String data = "\u2666";
+ byte[] bytes = data.getBytes("UTF-8");
+ String inconsistentString = new String(bytes, "ISO-8859-1");
+ Yaml yaml = new Yaml();
+ String payload = yaml.dump(inconsistentString);
+ // System.out.println("payload: '" + payload + "'");
+ String loaded = new String((byte[]) yaml.load(payload), "UTF-8");
+ assertEquals(inconsistentString, loaded);
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue163/LinearScalaTralingTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue163/LinearScalaTralingTest.java
new file mode 100644
index 0000000..6210f92
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue163/LinearScalaTralingTest.java
@@ -0,0 +1,43 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue163;
+
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+
+public class LinearScalaTralingTest extends TestCase {
+
+ public void testClipChomping() throws Exception {
+ String data = "testnode: |\n This is line 1\n This is line 2\n";
+ Yaml yaml = new Yaml();
+ @SuppressWarnings("unchecked")
+ Map<String, String> payload = (Map<String, String>) yaml.load(data);
+ assertEquals("This is line 1\nThis is line 2\n", payload.get("testnode"));
+ }
+
+ public void testStripChomping() throws Exception {
+ // mind the trailing '|-' to indicate strip chomping
+ String data = "testnode: |-\n This is line 1\n This is line 2\n";
+ Yaml yaml = new Yaml();
+ @SuppressWarnings("unchecked")
+ Map<String, String> payload = (Map<String, String>) yaml.load(data);
+ assertEquals("No traling line break expected.", "This is line 1\nThis is line 2",
+ payload.get("testnode"));
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue171/ClassWithGenericMap.java b/src/test/java/org/yaml/snakeyaml/issues/issue171/ClassWithGenericMap.java
new file mode 100644
index 0000000..5cfe7cc
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue171/ClassWithGenericMap.java
@@ -0,0 +1,24 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue171;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+class ClassWithGenericMap {
+ public final Map<String, Collection<Integer>> services = new HashMap<String, Collection<Integer>>();
+}
\ No newline at end of file
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue171/CustomRepresenter.java b/src/test/java/org/yaml/snakeyaml/issues/issue171/CustomRepresenter.java
new file mode 100644
index 0000000..093f90a
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue171/CustomRepresenter.java
@@ -0,0 +1,34 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue171;
+
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.Tag;
+import org.yaml.snakeyaml.representer.Represent;
+import org.yaml.snakeyaml.representer.Representer;
+
+class CustomRepresenter extends Representer {
+ public CustomRepresenter() {
+ this.representers.put(ClassWithGenericMap.class, new RepresentClassX());
+ }
+
+ private class RepresentClassX implements Represent {
+ public Node representData(Object data) {
+ ClassWithGenericMap classX = (ClassWithGenericMap) data;
+ return representMapping(Tag.MAP, classX.services, false);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue171/GenericExtendsObjectTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue171/GenericExtendsObjectTest.java
new file mode 100644
index 0000000..4ff2a49
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue171/GenericExtendsObjectTest.java
@@ -0,0 +1,36 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue171;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+
+public class GenericExtendsObjectTest extends TestCase {
+
+ public void testNoCompilationError() throws Exception {
+ Yaml yaml = new Yaml(new CustomRepresenter());
+ ClassWithGenericMap map = new ClassWithGenericMap();
+ List<Integer> list = new ArrayList<Integer>();
+ list.add(7);
+ map.services.put("wow", list);
+ String output = yaml.dump(map);
+ assertEquals("wow: [7]\n", output);
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue173/RecursiveAnchorTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue173/RecursiveAnchorTest.java
new file mode 100644
index 0000000..4571d1c
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue173/RecursiveAnchorTest.java
@@ -0,0 +1,54 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue173;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.representer.Representer;
+
+public class RecursiveAnchorTest extends TestCase {
+
+ public void testWithoutCustomStyle() throws Exception {
+ Map<String, Map<String, Object>> rootMap = new HashMap<String, Map<String, Object>>();
+ Map<String, Object> enclosedMap = new HashMap<String, Object>();
+ enclosedMap.put("world", "test");
+ rootMap.put("test", enclosedMap);
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(rootMap);
+ assertEquals("test: {world: test}\n", output);
+ }
+
+ public void testWithBlockStyle() throws Exception {
+ Map<String, Map<String, Object>> rootMap = new HashMap<String, Map<String, Object>>();
+ Map<String, Object> enclosedMap = new HashMap<String, Object>();
+ enclosedMap.put("world", "test");
+ rootMap.put("test", enclosedMap);
+
+ DumperOptions yamlOptions = new DumperOptions();
+ yamlOptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
+
+ Representer yamlRepresenter = new Representer();
+
+ Yaml yaml = new Yaml(yamlRepresenter, yamlOptions);
+ String output = yaml.dump(rootMap);
+ assertEquals("test:\n world: test\n", output);
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue176/SingleQuoteTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue176/SingleQuoteTest.java
new file mode 100644
index 0000000..be5a040
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue176/SingleQuoteTest.java
@@ -0,0 +1,63 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue176;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.DumperOptions.FlowStyle;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.SafeConstructor;
+import org.yaml.snakeyaml.representer.Representer;
+
+public class SingleQuoteTest extends TestCase {
+
+ public void testNoSingleQuoteForBlockStyle() throws Exception {
+ checkQuotes(true, "cows:\n steak:cow: '11'");
+ }
+
+ public void testSingleQuoteForFlowStyle() throws Exception {
+ checkQuotes(false, "cows: {'steak:cow': '11'}");
+ }
+
+ private void checkQuotes(boolean isBlock, String expectation) {
+ DumperOptions options = new DumperOptions();
+ options.setIndent(4);
+ if (isBlock) {
+ options.setDefaultFlowStyle(FlowStyle.BLOCK);
+ }
+ Representer representer = new Representer();
+
+ Yaml yaml = new Yaml(new SafeConstructor(), representer, options);
+
+ LinkedHashMap<String, Object> lvl1 = new LinkedHashMap<String, Object>();
+ lvl1.put("steak:cow", "11");
+ LinkedHashMap<String, Object> root = new LinkedHashMap<String, Object>();
+ root.put("cows", lvl1);
+ String output = yaml.dump(root);
+ assertEquals(expectation + "\n", output);
+
+ // parse the value back
+ @SuppressWarnings("unchecked")
+ Map<String, Object> cows = (Map<String, Object>) yaml.load(output);
+ @SuppressWarnings("unchecked")
+ Map<String, String> cow = (Map<String, String>) cows.get("cows");
+ assertEquals("11", cow.get("steak:cow"));
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue177/PointBean.java b/src/test/java/org/yaml/snakeyaml/issues/issue177/PointBean.java
new file mode 100644
index 0000000..ea46af9
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue177/PointBean.java
@@ -0,0 +1,26 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue177;
+
+public class PointBean {
+ public int x;
+ public int y;
+
+ @Override
+ public String toString() {
+ return "PointBean";
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue177/PointBeanTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue177/PointBeanTest.java
new file mode 100644
index 0000000..274cba3
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue177/PointBeanTest.java
@@ -0,0 +1,43 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue177;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+
+public class PointBeanTest extends TestCase {
+
+ public void testNoSingleQuoteForBlockStyle() throws Exception {
+ String input = Util.getLocalResource("issues/issue177-1.yaml");
+ try {
+ Yaml yaml = new Yaml();
+ yaml.load(input);
+ fail();
+ } catch (Exception e) {
+ assertEquals("Cannot create property=points for JavaBean=All Points\n"
+ + " in 'string', line 1, column 1:\n"
+ + " !!org.yaml.snakeyaml.issues.issu ... \n" + " ^\n"
+ + "Cannot create property=x for JavaBean=PointBean\n"
+ + " in 'string', line 7, column 5:\n" + " x: a\n" + " ^\n"
+ + "For input string: \"a\"\n" + " in 'string', line 7, column 8:\n"
+ + " x: a\n" + " ^\n" + "\n"
+ + " in 'string', line 3, column 3:\n" + " pt1:\n" + " ^\n",
+ e.getMessage());
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue177/Points.java b/src/test/java/org/yaml/snakeyaml/issues/issue177/Points.java
new file mode 100644
index 0000000..e0e57c5
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue177/Points.java
@@ -0,0 +1,27 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue177;
+
+import java.util.Map;
+
+public class Points {
+ public Map<String, PointBean> points;
+
+ @Override
+ public String toString() {
+ return "All Points";
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue182/InfinityFloatBean.java b/src/test/java/org/yaml/snakeyaml/issues/issue182/InfinityFloatBean.java
new file mode 100644
index 0000000..691959f
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue182/InfinityFloatBean.java
@@ -0,0 +1,21 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue182;
+
+public class InfinityFloatBean {
+ public float infinityFloat;
+ public Float infinityFloatObject;
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue182/InfinityFloatBeanTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue182/InfinityFloatBeanTest.java
new file mode 100644
index 0000000..f589f03
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue182/InfinityFloatBeanTest.java
@@ -0,0 +1,36 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue182;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+
+public class InfinityFloatBeanTest extends TestCase {
+
+ public void testInfinityFloatBean() throws Exception {
+
+ InfinityFloatBean bean = new InfinityFloatBean();
+ bean.infinityFloat = Float.POSITIVE_INFINITY;
+ bean.infinityFloatObject = Float.POSITIVE_INFINITY;
+
+ Yaml yaml = new Yaml();
+ String yamled = yaml.dump(bean);
+ InfinityFloatBean loadedBean = yaml.loadAs(yamled, InfinityFloatBean.class);
+ assertEquals(Float.POSITIVE_INFINITY, loadedBean.infinityFloat);
+ assertEquals(Float.POSITIVE_INFINITY, loadedBean.infinityFloatObject);
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue183/NumberBean.java b/src/test/java/org/yaml/snakeyaml/issues/issue183/NumberBean.java
new file mode 100644
index 0000000..0d49846
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue183/NumberBean.java
@@ -0,0 +1,20 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue183;
+
+public class NumberBean {
+ public Number number;
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue183/NumberBeanTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue183/NumberBeanTest.java
new file mode 100644
index 0000000..8200a01
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue183/NumberBeanTest.java
@@ -0,0 +1,95 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue183;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+
+public class NumberBeanTest extends TestCase {
+
+ public void testNumberBean() throws Exception {
+
+ NumberBean number = new NumberBean();
+ number.number = 1;
+
+ Yaml yaml = new Yaml();
+ String dump = yaml.dump(number);
+ NumberBean loaded = yaml.loadAs(dump, NumberBean.class);
+ assertEquals(new Long(1), loaded.number);
+ }
+
+ public void testNumberAsFloatInfinity() throws Exception {
+ NumberBean number = new NumberBean();
+ number.number = Float.POSITIVE_INFINITY;
+
+ Yaml yaml = new Yaml();
+ String dump = yaml.dump(number);
+ NumberBean loaded = yaml.loadAs(dump, NumberBean.class);
+ assertEquals(Float.POSITIVE_INFINITY, loaded.number.floatValue());
+ }
+
+ public void testNumberAsDoubleInfinity() throws Exception {
+ NumberBean number = new NumberBean();
+ number.number = Double.POSITIVE_INFINITY;
+
+ Yaml yaml = new Yaml();
+ String dump = yaml.dump(number);
+ NumberBean loaded = yaml.loadAs(dump, NumberBean.class);
+ assertEquals(Double.POSITIVE_INFINITY, loaded.number.doubleValue());
+ }
+
+ public void testNumberAsNegativeFloatInfinity() throws Exception {
+ NumberBean number = new NumberBean();
+ number.number = Float.NEGATIVE_INFINITY;
+
+ Yaml yaml = new Yaml();
+ String dump = yaml.dump(number);
+ NumberBean loaded = yaml.loadAs(dump, NumberBean.class);
+ assertEquals(Float.NEGATIVE_INFINITY, loaded.number.floatValue());
+ }
+
+ public void testNumberAsNegativeDoubleInfinity() throws Exception {
+ NumberBean number = new NumberBean();
+ number.number = Double.NEGATIVE_INFINITY;
+
+ Yaml yaml = new Yaml();
+ String dump = yaml.dump(number);
+ NumberBean loaded = yaml.loadAs(dump, NumberBean.class);
+ assertEquals(Double.NEGATIVE_INFINITY, loaded.number.doubleValue());
+ }
+
+ public void testNumberAsFloatNaN() throws Exception {
+ NumberBean number = new NumberBean();
+ number.number = Float.NaN;
+
+ Yaml yaml = new Yaml();
+ String dump = yaml.dump(number);
+ NumberBean loaded = yaml.loadAs(dump, NumberBean.class);
+ assertEquals(Float.NaN, loaded.number.floatValue());
+ }
+
+ public void testNumberAsDoubleNaN() throws Exception {
+ NumberBean number = new NumberBean();
+ number.number = Double.NaN;
+
+ Yaml yaml = new Yaml();
+ String dump = yaml.dump(number);
+ NumberBean loaded = yaml.loadAs(dump, NumberBean.class);
+ assertEquals(Double.NaN, loaded.number.doubleValue());
+ }
+
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue188/ErrorMessageTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue188/ErrorMessageTest.java
new file mode 100644
index 0000000..fa17b68
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue188/ErrorMessageTest.java
@@ -0,0 +1,35 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue188;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+
+public class ErrorMessageTest extends TestCase {
+
+ public void testErrorMessage() throws Exception {
+
+ try {
+ Yaml yaml = new Yaml();
+ String doc = "templates:\n" + " master:\n" + " type: Compute : invalid123";
+ yaml.load(doc);
+ fail();
+ } catch (Exception e) {
+ assertFalse(e.getMessage(), e.getMessage().contains("null"));
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue192/EqualsSignTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue192/EqualsSignTest.java
new file mode 100644
index 0000000..f48f7d1
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue192/EqualsSignTest.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue192;
+
+import junit.framework.TestCase;
+import org.yaml.snakeyaml.Yaml;
+
+public class EqualsSignTest extends TestCase {
+
+ public void testMappingNode() {
+ new Yaml().load("part1: =");
+ }
+
+ public void testScalarNode() {
+ new Yaml().load("=");
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue193/AbstractBeanTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue193/AbstractBeanTest.java
new file mode 100644
index 0000000..8476a6a
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue193/AbstractBeanTest.java
@@ -0,0 +1,52 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue193;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.BaseConstructor;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.introspector.BeanAccess;
+import org.yaml.snakeyaml.introspector.PropertyUtils;
+import org.yaml.snakeyaml.representer.Representer;
+
+public class AbstractBeanTest extends TestCase {
+
+ public void testErrorMessage() throws Exception {
+
+ BeanA1 b = new BeanA1();
+ b.setId(2l);
+ b.setName("name1");
+
+ Constructor c = new Constructor();
+ Representer r = new Representer();
+
+ PropertyUtils pu = new PropertyUtils();
+ c.setPropertyUtils(pu);
+ r.setPropertyUtils(pu);
+
+ pu.getProperties(BeanA1.class, BeanAccess.FIELD);
+
+ Yaml yaml = new Yaml(c, r);
+ // yaml.setBeanAccess(BeanAccess.FIELD);
+ String dump = yaml.dump(b);
+ BeanA1 b2 = (BeanA1) yaml.load(dump);
+ assertEquals(b.getId(), b2.getId());
+ assertEquals(b.getName(), b2.getName());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue193/BeanA.java b/src/test/java/org/yaml/snakeyaml/issues/issue193/BeanA.java
new file mode 100644
index 0000000..e2ab61b
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue193/BeanA.java
@@ -0,0 +1,22 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue193;
+
+public abstract class BeanA {
+
+ public abstract Object getId();
+
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue193/BeanA1.java b/src/test/java/org/yaml/snakeyaml/issues/issue193/BeanA1.java
new file mode 100644
index 0000000..f7b7719
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue193/BeanA1.java
@@ -0,0 +1,40 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue193;
+
+public class BeanA1 extends BeanA {
+
+ private Long id;
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ private String name;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue193/TestYaml.java b/src/test/java/org/yaml/snakeyaml/issues/issue193/TestYaml.java
new file mode 100644
index 0000000..662c74b
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue193/TestYaml.java
@@ -0,0 +1,68 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue193;
+
+import org.yaml.snakeyaml.Yaml;
+
+public class TestYaml {
+
+ public static abstract class BeanA {
+
+ public abstract Object getId();
+
+ }
+
+ public static class BeanA1 extends BeanA {
+
+ private Long id;
+
+ // @Override
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ private String name;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ }
+
+ public static void main(String[] args) {
+
+ System.out.println("test...");
+ BeanA1 b = new BeanA1();
+ b.setId(2l);
+ b.setName("name1");
+ Yaml yaml = new Yaml();
+ String dump = yaml.dump(b);
+
+ System.out.println("dump:" + dump);
+
+ dump = "!!org.yaml.snakeyaml.issues.issue193.TestYaml$BeanA1 {id: 2, name: name1}";
+
+ yaml.load(dump);
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue203/ContentIdentifier.java b/src/test/java/org/yaml/snakeyaml/issues/issue203/ContentIdentifier.java
new file mode 100644
index 0000000..0557412
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue203/ContentIdentifier.java
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue203;
+
+public interface ContentIdentifier extends Identifiable<Long> {};
+
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue203/ContentIdentifierImpl.java b/src/test/java/org/yaml/snakeyaml/issues/issue203/ContentIdentifierImpl.java
new file mode 100644
index 0000000..b4c10f8
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue203/ContentIdentifierImpl.java
@@ -0,0 +1,29 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue203;
+
+public class ContentIdentifierImpl implements ContentIdentifier {
+
+ private Long id;
+
+ public ContentIdentifierImpl(Long id) {
+ this.id = id;
+ }
+
+ public Long getId() {
+ return id;
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue203/DataBean.java b/src/test/java/org/yaml/snakeyaml/issues/issue203/DataBean.java
new file mode 100644
index 0000000..dc96d04
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue203/DataBean.java
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue203;
+
+public class DataBean {
+ private String id;
+ private ContentIdentifier content;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+
+ public ContentIdentifier getContent() {
+ return content;
+ }
+
+ public void setContent(ContentIdentifier content) {
+ this.content = content;
+ }
+
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue203/GenericTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue203/GenericTest.java
new file mode 100644
index 0000000..165fbe6
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue203/GenericTest.java
@@ -0,0 +1,32 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue203;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+
+public class GenericTest extends TestCase {
+
+ public void testGenericInterface() {
+ Yaml yaml = new Yaml();
+ String uuu = "!!org.yaml.snakeyaml.issues.issue203.DataBean\n"
+ + "content: !!org.yaml.snakeyaml.issues.issue203.ContentIdentifierImpl 33\n"
+ + "id: 555";
+ DataBean obj = (DataBean) yaml.load(uuu);
+ assertEquals(33, obj.getContent().getId().intValue());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue203/Identifiable.java b/src/test/java/org/yaml/snakeyaml/issues/issue203/Identifiable.java
new file mode 100644
index 0000000..dbe1ffe
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue203/Identifiable.java
@@ -0,0 +1,22 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue203;
+
+import java.io.Serializable;
+
+public interface Identifiable<ID extends Serializable> {
+ public ID getId();
+}
\ No newline at end of file
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue205/AppleSmileTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue205/AppleSmileTest.java
new file mode 100644
index 0000000..f17556e
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue205/AppleSmileTest.java
@@ -0,0 +1,36 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue205;
+
+import junit.framework.TestCase;
+import org.yaml.snakeyaml.Yaml;
+
+import java.io.InputStream;
+
+public class AppleSmileTest extends TestCase {
+
+ public void testEmoji() {
+ //http://support.apple.com/en-us/ht4976
+ InputStream input = Thread.currentThread().getContextClassLoader().getResourceAsStream("issues/ios_emoji_surrogate.yaml");
+ Yaml yaml = new Yaml();
+ try {
+ yaml.load(input);
+ fail("Surrogate characters must not be accepted.");
+ } catch (Exception e) {
+ assertEquals("special characters are not allowed", e.getMessage());
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue207/OctalNumberTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue207/OctalNumberTest.java
new file mode 100644
index 0000000..82dd5d5
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue207/OctalNumberTest.java
@@ -0,0 +1,41 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue207;
+
+import junit.framework.TestCase;
+import org.yaml.snakeyaml.Yaml;
+
+import java.io.InputStream;
+import java.util.Map;
+
+public class OctalNumberTest extends TestCase {
+
+ public void testOctalNumbersMoreThenSeven() {
+ Yaml yaml = new Yaml();
+ assertEquals(7, yaml.load("07"));
+ assertEquals(63, yaml.load("077"));
+ assertEquals(0, yaml.load("0"));
+ assertEquals("0A", yaml.load("0A"));
+ assertEquals("09", yaml.load("!!str 09"));
+
+ /* TODO fix 207 and 130
+ assertEquals("08", yaml.load("08"));
+ assertEquals("09", yaml.load("09"));
+ Map<String, String> parsed9 = (Map<String, String>) yaml.load("a: 09");
+ assertEquals("09", parsed9.get("a"));
+ */
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue24/LineNumberTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue24/LineNumberTest.java
new file mode 100644
index 0000000..3ea8ead
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue24/LineNumberTest.java
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue24;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+
+/**
+ * to test http://code.google.com/p/snakeyaml/issues/detail?id=24
+ */
+public class LineNumberTest extends TestCase {
+ public void test1() {
+ String resource = Util.getLocalResource("issues/issue24-1.yaml");
+ // System.out.println(resource);
+ Yaml yaml = new Yaml();
+ try {
+ yaml.load(resource);
+ fail();
+ } catch (Exception e) {
+ assertTrue(e.toString(), e.toString().contains("line 3"));
+ assertTrue(e.toString(), e.toString().contains("column 12"));
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue29/BigJavaBean.java b/src/test/java/org/yaml/snakeyaml/issues/issue29/BigJavaBean.java
new file mode 100644
index 0000000..5141662
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue29/BigJavaBean.java
@@ -0,0 +1,127 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue29;
+
+import java.util.List;
+import java.util.Map;
+
+public class BigJavaBean {
+ private String name;
+ private String address;
+ private String description;
+ private int id;
+ private List<Integer> numbers;
+ private Map<String, String> data;
+
+ public BigJavaBean() {
+ }
+
+ public BigJavaBean(int id, String name, String address, String description) {
+ super();
+ this.name = name;
+ this.address = address;
+ this.description = description;
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getAddress() {
+ return address;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public List<Integer> getNumbers() {
+ return numbers;
+ }
+
+ public void setNumbers(List<Integer> numbers) {
+ this.numbers = numbers;
+ }
+
+ public Map<String, String> getData() {
+ return data;
+ }
+
+ public void setData(Map<String, String> data) {
+ this.data = data;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((address == null) ? 0 : address.hashCode());
+ result = prime * result + ((data == null) ? 0 : data.hashCode());
+ result = prime * result + ((description == null) ? 0 : description.hashCode());
+ result = prime * result + id;
+ result = prime * result + ((name == null) ? 0 : name.hashCode());
+ result = prime * result + ((numbers == null) ? 0 : numbers.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ BigJavaBean other = (BigJavaBean) obj;
+ if (address == null) {
+ if (other.address != null)
+ return false;
+ } else if (!address.equals(other.address))
+ return false;
+ if (data == null) {
+ if (other.data != null)
+ return false;
+ } else if (!data.equals(other.data))
+ return false;
+ if (description == null) {
+ if (other.description != null)
+ return false;
+ } else if (!description.equals(other.description))
+ return false;
+ if (id != other.id)
+ return false;
+ if (name == null) {
+ if (other.name != null)
+ return false;
+ } else if (!name.equals(other.name))
+ return false;
+ if (numbers == null) {
+ if (other.numbers != null)
+ return false;
+ } else if (!numbers.equals(other.numbers))
+ return false;
+ return true;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue29/FlexibleScalarStyleTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue29/FlexibleScalarStyleTest.java
new file mode 100644
index 0000000..384b83d
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue29/FlexibleScalarStyleTest.java
@@ -0,0 +1,116 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue29;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.DumperOptions.ScalarStyle;
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.ScalarNode;
+import org.yaml.snakeyaml.representer.Representer;
+
+/**
+ * to test http://code.google.com/p/snakeyaml/issues/detail?id=29
+ */
+public class FlexibleScalarStyleTest extends TestCase {
+ public void testLong() {
+ DumperOptions options = new DumperOptions();
+ options.setDefaultScalarStyle(ScalarStyle.FOLDED);
+ Yaml yaml = new Yaml(options);
+ String result = yaml
+ .dump("qqqqqqqqqqqqqqqqqq qqqqqqqqqqqqqqqqqqqqqqqqq qqqqqqqqqqqqqqqqqqqqqqqq "
+ + "qqqqqqqqqqqqqqqqqqqqqqqq qqqqqqqqqqqqqqqqqqqqqqqq "
+ + "qqqqqqqqqqqqqqqqqqqqqqqqq 111111111111111111111111\n "
+ + "qqqqqqqqqqqqqqqqqqqqqqqqqqqqq qqqqqqqqqqqqqqqqqqqqqqqqqqq\n");
+ // System.out.println(result);
+ assertTrue(result.startsWith(">\n"));
+ assertEquals(
+ ">\n qqqqqqqqqqqqqqqqqq qqqqqqqqqqqqqqqqqqqqqqqqq qqqqqqqqqqqqqqqqqqqqqqqq qqqqqqqqqqqqqqqqqqqqqqqq\n qqqqqqqqqqqqqqqqqqqqqqqq qqqqqqqqqqqqqqqqqqqqqqqqq 111111111111111111111111\n qqqqqqqqqqqqqqqqqqqqqqqqqqqqq qqqqqqqqqqqqqqqqqqqqqqqqqqq\n",
+ result);
+ }
+
+ public void testNoFoldedScalar() {
+ DumperOptions options = new DumperOptions();
+ options.setWidth(30);
+ Yaml yaml = new Yaml(options);
+ String output = yaml.dump(getData());
+ // System.out.println(output);
+ String etalon = Util.getLocalResource("representer/scalar-style1.yaml");
+ assertEquals(etalon, output);
+ }
+
+ public void testCustomScalarStyle() {
+ DumperOptions options = new DumperOptions();
+ options.setWidth(30);
+ Yaml yaml = new Yaml(new MyRepresenter(), options);
+ String output = yaml.dump(getData());
+ // System.out.println(output);
+ String etalon = Util.getLocalResource("representer/scalar-style2.yaml");
+ assertEquals(etalon, output);
+ }
+
+ public void testCustomScalarStyleNoSplitLines() {
+ DumperOptions options = new DumperOptions();
+ options.setWidth(30);
+ options.setSplitLines(false);
+ Yaml yaml = new Yaml(new MyRepresenter(), options);
+ String output = yaml.dump(getData());
+ // System.out.println(output);
+ String etalon = Util.getLocalResource("representer/scalar-style3.yaml");
+ assertEquals(etalon, output);
+ }
+
+ private Map<String, String> getData() {
+ Map<String, String> map = new LinkedHashMap<String, String>();
+ map.put("name", "Steve Jobs");
+ map.put("address", "Name\nStreet Number\nCountry");
+ map.put("description",
+ "1111111111 2222222222 3333333333 4444444444 5555555555 6666666666 7777777777 8888888888 9999999999 0000000000");
+ return map;
+ }
+
+ private class MyRepresenter extends Representer {
+
+ public MyRepresenter() {
+ super();
+ this.representers.put(String.class, new FlexibleRepresent());
+ }
+
+ private class FlexibleRepresent extends RepresentString {
+ public Node representData(Object data) {
+ ScalarNode node = (ScalarNode) super.representData(data);
+ if (node.getStyle() == null) {
+ // if Plain scalar style
+ if (node.getValue().length() < 25) {
+ return node;
+ } else {
+ // Folded scalar style
+ return new ScalarNode(node.getTag(), node.getValue(), node.getStartMark(),
+ node.getEndMark(), '>');
+ }
+ } else {
+ return node;
+ }
+ }
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue29/FlexibleScalarStylesInJavaBeanTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue29/FlexibleScalarStylesInJavaBeanTest.java
new file mode 100644
index 0000000..afddbc8
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue29/FlexibleScalarStylesInJavaBeanTest.java
@@ -0,0 +1,147 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue29;
+
+import java.beans.IntrospectionException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.introspector.BeanAccess;
+import org.yaml.snakeyaml.introspector.Property;
+import org.yaml.snakeyaml.nodes.NodeTuple;
+import org.yaml.snakeyaml.nodes.ScalarNode;
+import org.yaml.snakeyaml.nodes.SequenceNode;
+import org.yaml.snakeyaml.nodes.Tag;
+import org.yaml.snakeyaml.representer.Representer;
+
+public class FlexibleScalarStylesInJavaBeanTest extends TestCase {
+ public void testDifferentStyles() {
+ BigJavaBean bean1 = new BigJavaBean(1, "simple", "line 1\nline2\nzipcode", "short text1");
+ List<Integer> numbers1 = new ArrayList<Integer>(Arrays.asList(1, 2, 3));
+ bean1.setNumbers(numbers1);
+ Map<String, String> data1 = new HashMap<String, String>();
+ data1.put("key1", "value1");
+ data1.put("key2", "value2");
+ bean1.setData(data1);
+ //
+ BigJavaBean bean2 = new BigJavaBean(1, "second", "line 111\nline 222\nzipcode 12345\n\n",
+ "info: semicolon is used");
+ List<Integer> numbers2 = new ArrayList<Integer>(Arrays.asList(4, 5, 6, 777, 888, 999, 1000));
+ bean2.setNumbers(numbers2);
+ Map<String, String> data2 = new HashMap<String, String>();
+ data2.put("key21", "value12");
+ data2.put("key22", "value with\ntwo lines");
+ bean2.setData(data2);
+ //
+ List<BigJavaBean> list = new ArrayList<BigJavaBean>();
+ list.add(bean1);
+ list.add(bean2);
+ Yaml yaml = new Yaml(new MyRepresenter());
+ yaml.setBeanAccess(BeanAccess.FIELD);
+ String output = yaml.dump(list);
+ // System.out.println(output);
+ // parse back
+ @SuppressWarnings("unchecked")
+ List<BigJavaBean> parsed = (List<BigJavaBean>) yaml.load(output);
+ assertEquals(2, parsed.size());
+ assertEquals(bean1, parsed.get(0));
+ assertEquals(bean2, parsed.get(1));
+
+ }
+
+ private class MyRepresenter extends Representer {
+ /*
+ * Change the default order. Important data goes first.
+ */
+ @Override
+ protected Set<Property> getProperties(Class<? extends Object> type)
+ throws IntrospectionException {
+ if (type.isAssignableFrom(BigJavaBean.class)) {
+ Set<Property> standard = super.getProperties(type);
+ Set<Property> sorted = new TreeSet<Property>(new PropertyComparator());
+ sorted.addAll(standard);
+ return sorted;
+ } else {
+ return super.getProperties(type);
+ }
+ }
+
+ private class PropertyComparator implements Comparator<Property> {
+ public int compare(Property o1, Property o2) {
+ // important go first
+ List<String> order = new ArrayList<String>(Arrays.asList("id", "name",
+ "description", "address"));
+ for (String name : order) {
+ int c = compareByName(o1, o2, name);
+ if (c != 0) {
+ return c;
+ }
+ }
+ // all the rest
+ return o1.compareTo(o2);
+ }
+
+ private int compareByName(Property o1, Property o2, String name) {
+ if (o1.getName().equals(name)) {
+ return -1;
+ } else if (o2.getName().equals(name)) {
+ return 1;
+ }
+ return 0;// compare further
+ }
+ }
+
+ @Override
+ protected NodeTuple representJavaBeanProperty(Object javaBean, Property property,
+ Object propertyValue, Tag customTag) {
+ if (javaBean instanceof BigJavaBean) {
+ BigJavaBean bean = (BigJavaBean) javaBean;
+ NodeTuple standard = super.representJavaBeanProperty(javaBean, property,
+ propertyValue, customTag);
+ if (property.getName().equals("numbers")) {
+ // when the list is small, make it block collection style
+ if (bean.getNumbers().size() < 5) {
+ SequenceNode n = (SequenceNode) standard.getValueNode();
+ return new NodeTuple(standard.getKeyNode(), new SequenceNode(n.getTag(),
+ true, n.getValue(), n.getStartMark(), n.getEndMark(), false));
+ }
+ }
+ if (property.getName().equals("description")) {
+ // if description contains ':' use folded scalar style and
+ // not single quoted scalar style
+ if (bean.getDescription().indexOf(':') > 0) {
+ ScalarNode n = (ScalarNode) standard.getValueNode();
+ return new NodeTuple(standard.getKeyNode(), new ScalarNode(n.getTag(),
+ n.getValue(), n.getStartMark(), n.getEndMark(), '>'));
+ }
+ }
+ return standard;
+ } else {
+ return super
+ .representJavaBeanProperty(javaBean, property, propertyValue, customTag);
+ }
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue306/BeanWithId.java b/src/test/java/org/yaml/snakeyaml/issues/issue306/BeanWithId.java
new file mode 100644
index 0000000..40f849e
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue306/BeanWithId.java
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue306;
+
+import java.util.UUID;
+
+public class BeanWithId {
+ private int value;
+ private UUID id;
+
+ public int getValue() {
+ return value;
+ }
+
+ public void setValue(int value) {
+ this.value = value;
+ }
+
+ public UUID getId() {
+ return id;
+ }
+
+ public void setId(UUID id) {
+ this.id = id;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue306/UuidSupportTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue306/UuidSupportTest.java
new file mode 100644
index 0000000..3622868
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue306/UuidSupportTest.java
@@ -0,0 +1,88 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue306;
+
+import org.junit.Test;
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.nodes.Tag;
+
+import java.util.UUID;
+import java.util.regex.Pattern;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class UuidSupportTest {
+
+ public static final Pattern UUID_PATTERN = Pattern
+ .compile("^(?:\\p{XDigit}{8}-\\p{XDigit}{4}-\\p{XDigit}{4}-\\p{XDigit}{4}-\\p{XDigit}{12})$");
+ public static final Tag UUID_TAG = new Tag(Tag.PREFIX + "java.util.UUID");
+
+ @Test
+ public void pattern() {
+ assertTrue(UUID_PATTERN.matcher("7f511847-781a-45df-9c8d-1e32e028b9b3").matches());
+ assertTrue(UUID_PATTERN.matcher("AC4877BE-0C31-4458-A86E-0272EFE1AAA8").matches());
+ }
+
+ @Test
+ public void dumpAsString() {
+ UUID uuid = UUID.randomUUID();
+ String str = uuid.toString();
+ Yaml yaml = new Yaml();
+ yaml.addImplicitResolver(UUID_TAG, UUID_PATTERN, null);
+ String output = yaml.dump(str);
+ assertEquals("'" + str + "'\n", output);
+ assertEquals(str + "\n", yaml.dump(uuid));
+ }
+
+ @Test
+ public void loadAsUuid() {
+ Yaml yaml = new Yaml();
+ yaml.addImplicitResolver(UUID_TAG, UUID_PATTERN, null);
+ UUID uuid = (UUID) yaml.load("7f511847-781a-45df-9c8d-1e32e028b9b3");
+ assertEquals("7f511847-781a-45df-9c8d-1e32e028b9b3", uuid.toString());
+ }
+
+ @Test
+ public void loadFromBean() {
+ String input = Util.getLocalResource("issues/issue306-1.yaml");
+ Yaml yaml = new Yaml();
+ BeanWithId bean = yaml.loadAs(input, BeanWithId.class);
+ assertEquals("7f511847-781a-45df-9c8d-1e32e028b9b3", bean.getId().toString());
+ }
+
+ @Test
+ public void dumpUuid() {
+ UUID uuid = UUID.randomUUID();
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(uuid);
+ assertEquals("!!java.util.UUID '" + uuid.toString() + "'\n", output);
+ }
+
+ @Test
+ public void dumpBean() {
+ BeanWithId bean = new BeanWithId();
+ bean.setValue(3);
+ UUID uuid = UUID.fromString("ac4877be-0c31-4458-a86e-0272efe1aaa8");
+ bean.setId(uuid);
+ Yaml yaml = new Yaml();
+ String output = yaml.dumpAs(bean, Tag.MAP, DumperOptions.FlowStyle.BLOCK);
+ String expected = Util.getLocalResource("issues/issue306-2.yaml");
+ assertEquals(expected, output);
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue310/Option.java b/src/test/java/org/yaml/snakeyaml/issues/issue310/Option.java
new file mode 100644
index 0000000..9c0cddb
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue310/Option.java
@@ -0,0 +1,34 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue310;
+
+public final class Option<T> {
+
+ private final T value;
+
+ public static <T> Option<T> valueOf(T v) {
+ return new Option<T>(v);
+ }
+
+ private Option(T v) {
+ this.value = v;
+ }
+
+ public T getValue() {
+ return value;
+ }
+
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue310/Person.java b/src/test/java/org/yaml/snakeyaml/issues/issue310/Person.java
new file mode 100644
index 0000000..c18cde2
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue310/Person.java
@@ -0,0 +1,46 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue310;
+
+public class Person {
+
+ private final int id;
+ private final String name;
+ private final Option<Double> income;
+
+ public Person() {
+ this(0, "", Option.valueOf(0.));
+ }
+
+ public Person(int id, String name, Option<Double> income) {
+ this.id = id;
+ this.name = name;
+ this.income = income;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Option<Double> getIncome() {
+ return income;
+ }
+
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue310/PropertyWithPrivateCostructorTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue310/PropertyWithPrivateCostructorTest.java
new file mode 100644
index 0000000..cb52762
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue310/PropertyWithPrivateCostructorTest.java
@@ -0,0 +1,75 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue310;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.introspector.BeanAccess;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.representer.Represent;
+import org.yaml.snakeyaml.representer.Representer;
+
+public class PropertyWithPrivateCostructorTest {
+
+ public static class OptionRepresenter extends Representer {
+
+ public OptionRepresenter() {
+ this.representers.put(Option.class, new RepresentOption());
+ }
+
+ private class RepresentOption implements Represent {
+ public Node representData(Object data) {
+ Option<?> opt = (Option<?>) data;
+ return represent(opt.getValue());
+ }
+ }
+
+ }
+
+ @Test
+ public void loadFromString() {
+
+ String yamlStr = "id: 123\n" + "income: 123456.78\n" + "name: Neo Anderson";
+
+ Person loadedPerson = yaml().loadAs(yamlStr, Person.class);
+
+ assertEquals("id", loadedPerson.getId(), 123);
+ assertEquals("name", loadedPerson.getName(), "Neo Anderson");
+ assertEquals("income", loadedPerson.getIncome().getValue().doubleValue(), 123456.78, 0.);
+ }
+
+ @Test
+ public void dumpNload() {
+
+ Person person = new Person(123, "Neo Anderson", Option.valueOf(123456.78));
+
+ String dump = yaml().dumpAsMap(person);
+
+ Person loadedPerson = yaml().loadAs(dump, Person.class);
+
+ assertEquals("id", loadedPerson.getId(), 123);
+ assertEquals("name", loadedPerson.getName(), "Neo Anderson");
+ assertEquals("income", loadedPerson.getIncome().getValue().doubleValue(), 123456.78, 0.);
+ }
+
+ private Yaml yaml() {
+ Yaml _yaml = new Yaml(new OptionRepresenter());
+ _yaml.setBeanAccess(BeanAccess.FIELD);
+ return _yaml;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue311/BeanWithEnum.java b/src/test/java/org/yaml/snakeyaml/issues/issue311/BeanWithEnum.java
new file mode 100644
index 0000000..7bd5e2c
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue311/BeanWithEnum.java
@@ -0,0 +1,57 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue311;
+
+public class BeanWithEnum {
+
+ private boolean boolField;
+ private String name;
+ private BooleanEnum enumField;
+
+ public BeanWithEnum() {
+ this(true, "", BooleanEnum.UNKNOWN);
+ }
+
+ public BeanWithEnum(boolean boolField, String name, BooleanEnum enumField) {
+ this.boolField = boolField;
+ this.name = name;
+ this.enumField = enumField;
+ }
+
+ public boolean isBoolField() {
+ return boolField;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public BooleanEnum getEnumField() {
+ return enumField;
+ }
+
+ public void setBoolField(boolean boolField) {
+ this.boolField = boolField;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public void setEnumField(BooleanEnum enumField) {
+ this.enumField = enumField;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue311/BooleanEnum.java b/src/test/java/org/yaml/snakeyaml/issues/issue311/BooleanEnum.java
new file mode 100644
index 0000000..f37aabd
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue311/BooleanEnum.java
@@ -0,0 +1,45 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue311;
+
+public enum BooleanEnum {
+
+ TRUE(true), FALSE(false), UNKNOWN();
+
+ private boolean boolValue;
+ private boolean defined;
+
+ BooleanEnum(boolean p) {
+ boolValue = p;
+ defined = true;
+ }
+
+ BooleanEnum() {
+ boolValue = false;
+ defined = false;
+ }
+
+ boolean getBoolValue() {
+ if (!defined)
+ throw new IllegalArgumentException("Undefined has no value");
+ else
+ return boolValue;
+ }
+
+ boolean isDefined() {
+ return defined;
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue311/BooleanEnumTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue311/BooleanEnumTest.java
new file mode 100644
index 0000000..3f0107a
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue311/BooleanEnumTest.java
@@ -0,0 +1,112 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue311;
+
+import org.junit.Test;
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.NodeId;
+import org.yaml.snakeyaml.nodes.ScalarNode;
+import org.yaml.snakeyaml.nodes.Tag;
+import org.yaml.snakeyaml.representer.Represent;
+import org.yaml.snakeyaml.representer.Representer;
+
+import static org.junit.Assert.assertEquals;
+
+public class BooleanEnumTest {
+
+ @Test
+ public void loadEnum() {
+
+ Yaml yaml = new Yaml(new MyConstructor(), new MyRepresenter());
+ BeanWithEnum parsed = yaml.loadAs("{boolField: true, enumField: true, name: '10'}", BeanWithEnum.class);
+ //System.out.println(parsed.getEnumField());
+ assertEquals(BooleanEnum.TRUE, parsed.getEnumField());
+ assertEquals("10", parsed.getName());
+ }
+
+ @Test
+ public void loadEnumUndefined() {
+
+ Yaml yaml = new Yaml(new MyConstructor(), new MyRepresenter());
+ BeanWithEnum parsed = yaml.loadAs("{boolField: true, enumField: nonsense, name: bar}", BeanWithEnum.class);
+ //System.out.println(parsed.getEnumField());
+ assertEquals(BooleanEnum.UNKNOWN, parsed.getEnumField());
+ assertEquals("bar", parsed.getName());
+ }
+
+ @Test
+ public void dumpEnum() {
+
+ BeanWithEnum bean = new BeanWithEnum(true, "10", BooleanEnum.TRUE);
+ Yaml yaml = new Yaml(new MyConstructor(), new MyRepresenter());
+ String output = yaml.dumpAs(bean, Tag.MAP, DumperOptions.FlowStyle.FLOW);
+ assertEquals("{boolField: true, enumField: 'true', name: '10'}\n", output);
+ }
+
+ class MyRepresenter extends Representer {
+ public MyRepresenter() {
+ this.representers.put(BooleanEnum.class, new RepresentEnum());
+ }
+
+ private class RepresentEnum implements Represent {
+ public Node representData(Object data) {
+ BooleanEnum myEnum = (BooleanEnum) data;
+ String value;
+ switch (myEnum) {
+ case TRUE:
+ value = "true";
+ break;
+
+ case FALSE:
+ value = "false";
+ break;
+
+ case UNKNOWN:
+ value = "unknown";
+ break;
+
+ default:
+ throw new IllegalArgumentException();
+ }
+ return representScalar(Tag.STR, value);
+ }
+ }
+ }
+
+ class MyConstructor extends Constructor {
+ public MyConstructor() {
+ this.yamlClassConstructors.put(NodeId.scalar, new ConstructEnum());
+ }
+
+ private class ConstructEnum extends ConstructScalar {
+ public Object construct(Node node) {
+ if (node.getType().equals(BooleanEnum.class)) {
+ String val = (String) constructScalar((ScalarNode) node);
+ if ("true".equals(val)) {
+ return BooleanEnum.TRUE;
+ } else if ("false".equals(val)) {
+ return BooleanEnum.FALSE;
+ } else
+ return BooleanEnum.UNKNOWN;
+ }
+ return super.construct(node);
+ }
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue318/ContextClassLoaderTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue318/ContextClassLoaderTest.java
new file mode 100644
index 0000000..82f29ee
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue318/ContextClassLoaderTest.java
@@ -0,0 +1,136 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue318;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Properties;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.yaml.snakeyaml.Yaml;
+
+public class ContextClassLoaderTest {
+
+ static public class DomainBean {
+
+ private int value = 0;
+
+ public void setValue(int value) {
+ this.value = value;
+ }
+
+ public int getValue() {
+ return value;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + value;
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ DomainBean other = (DomainBean) obj;
+ if (value != other.value)
+ return false;
+ return true;
+ }
+
+ }
+
+ private URLClassLoader yamlCL;
+
+ @Before
+ public void before() throws MalformedURLException {
+ Properties classpath = new Properties();
+ InputStream cpProperties = getClass().getResourceAsStream("classpath.properties");
+ try {
+ classpath.load(cpProperties);
+ } catch (IOException e2) {
+ fail(e2.getLocalizedMessage());
+ }
+
+ File runtimeClassesDir = new File(classpath.getProperty("runtime_classes_dir"));
+
+ yamlCL = new URLClassLoader(new URL[] { runtimeClassesDir.toURI().toURL() }, null);
+ }
+
+ @After
+ public void after() {
+ // URLClassLoader.close is @since 1.7
+ // if (yamlCL != null) {
+ // try {
+ // yamlCL.close();
+ // } catch (IOException e) {
+ // e.printStackTrace();
+ // } finally {
+ yamlCL = null;
+ // }
+ // }
+ }
+
+ @Test(expected = ClassNotFoundException.class)
+ public void expectNoDomainClassInYamlCL() throws ClassNotFoundException {
+ yamlCL.loadClass(DomainBean.class.getName());
+ }
+
+ @Test
+ public void yamlClassInYAMLCL() throws ClassNotFoundException {
+ yamlCL.loadClass(Yaml.class.getName());
+ }
+
+ @Test
+ public void domainInDifferentConstructor() throws ClassNotFoundException,
+ InstantiationException, IllegalAccessException, NoSuchMethodException,
+ SecurityException, IllegalArgumentException, InvocationTargetException {
+
+ Class<?> yamlClass = yamlCL.loadClass(Yaml.class.getName());
+
+ DomainBean bean = new DomainBean();
+ bean.setValue(13);
+
+ Object yaml = yamlClass.newInstance();
+
+ Method dumpMethod = yaml.getClass().getMethod("dump", new Class<?>[] { Object.class });
+ String dump = dumpMethod.invoke(yaml, bean).toString();
+
+ Method loadMethod = yaml.getClass().getMethod("load", new Class<?>[] { String.class });
+ DomainBean object = (DomainBean) loadMethod.invoke(yaml, dump);
+
+ assertEquals(bean, object);
+ }
+
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue332/Data.java b/src/test/java/org/yaml/snakeyaml/issues/issue332/Data.java
new file mode 100644
index 0000000..56eeb4c
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue332/Data.java
@@ -0,0 +1,70 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue332;
+
+import java.beans.ConstructorProperties;
+import java.math.BigDecimal;
+
+public class Data {
+ private String label;
+
+ private String unit;
+
+ private BigDecimal value;
+
+ public BigDecimal getValue() {
+ return value;
+ }
+
+ public String getLabel() {
+ return label;
+ }
+
+ @ConstructorProperties({"label", "value", "unit"})
+ public Data(String label, BigDecimal value, String unit) {
+ this.label = label;
+ this.value = value;
+ this.unit = unit;
+ }
+
+// public void setLabel(String label) {
+// this.label = label;
+// }
+//
+// public void setUnit(String unit) {
+// this.unit = unit;
+// }
+//
+// public void setValue(BigDecimal value) {
+// this.value = value;
+// }
+
+ public String getUnit() {
+ return unit;
+ }
+
+ public Data() {
+ }
+
+ @Override
+ public String toString() {
+ return "Data{" +
+ "label='" + label + '\'' +
+ ", unit='" + unit + '\'' +
+ ", value=" + value +
+ '}';
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue332/DataTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue332/DataTest.java
new file mode 100644
index 0000000..6b6098d
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue332/DataTest.java
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue332;
+
+import org.junit.Test;
+import org.yaml.snakeyaml.Yaml;
+
+import java.math.BigDecimal;
+
+import static org.junit.Assert.assertEquals;
+
+public class DataTest {
+
+ @Test
+ public void testGetUnit() throws Exception {
+ Data data = new Data("Voltage", BigDecimal.TEN, "V");
+ assertEquals("!!org.yaml.snakeyaml.issues.issue332.Data {}", new Yaml().dump(data).trim());
+ //TODO assertEquals("!!org.yaml.snakeyaml.issues.issue332.Data {label: Voltage, unit: V, value: !!float '10'}", new Yaml().dump(data).trim());
+ }
+
+ @Test
+ public void testLoad() throws Exception {
+ String doc = "!!org.yaml.snakeyaml.issues.issue332.Data [Voltage, 10, volts]";
+ assertEquals("Data{label='Voltage', unit='volts', value=10}", (new Yaml().load(doc)).toString());
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue38/Bean.java b/src/test/java/org/yaml/snakeyaml/issues/issue38/Bean.java
new file mode 100644
index 0000000..d644561
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue38/Bean.java
@@ -0,0 +1,50 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue38;
+
+public class Bean {
+ int value;
+
+ public Bean() {
+ }
+
+ public Bean(int value) {
+ this.value = value;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return toString().equals(obj.toString());
+ }
+
+ @Override
+ public int hashCode() {
+ return value;
+ }
+
+ @Override
+ public String toString() {
+ return "Bean " + String.valueOf(value);
+ }
+
+ public int getValue() {
+ return value;
+ }
+
+ public void setValue(int value) {
+ this.value = value;
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue38/BigNumberIdTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue38/BigNumberIdTest.java
new file mode 100644
index 0000000..d80168a
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue38/BigNumberIdTest.java
@@ -0,0 +1,46 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue38;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+
+/**
+ * to test http://code.google.com/p/snakeyaml/issues/detail?id=38
+ */
+public class BigNumberIdTest extends TestCase {
+ @SuppressWarnings("unchecked")
+ public void testBigNumberFormat() {
+ List<Bean> list = new ArrayList<Bean>(2000);
+ for (int i = 1; i < 1010; i++) {
+ Bean value = new Bean(i);
+ list.add(value);
+ list.add(value);
+ }
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(list);
+ // System.out.println(output);
+ //
+ List<Bean> list2 = (List<Bean>) yaml.load(output);
+ for (Bean bean : list2) {
+ assertTrue(bean.getValue() > 0);
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue40/DogFoodBean.java b/src/test/java/org/yaml/snakeyaml/issues/issue40/DogFoodBean.java
new file mode 100644
index 0000000..e0c7dab
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue40/DogFoodBean.java
@@ -0,0 +1,34 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue40;
+
+import java.math.BigDecimal;
+
+public class DogFoodBean {
+ BigDecimal decimal;
+
+ public DogFoodBean() {
+ decimal = BigDecimal.ZERO;
+ }
+
+ public BigDecimal getDecimal() {
+ return decimal;
+ }
+
+ public void setDecimal(BigDecimal decimal) {
+ this.decimal = decimal;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue40/DogFoodBeanTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue40/DogFoodBeanTest.java
new file mode 100644
index 0000000..f0891e1
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue40/DogFoodBeanTest.java
@@ -0,0 +1,72 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue40;
+
+import java.math.BigDecimal;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+
+public class DogFoodBeanTest extends TestCase {
+
+ public void testOwnBigDecimal() {
+ DogFoodBean input = new DogFoodBean();
+ input.setDecimal(new BigDecimal("5"));
+ Yaml yaml = new Yaml();
+ String text = yaml.dump(input);
+ // System.out.println(text);
+ assertEquals("!!org.yaml.snakeyaml.issues.issue40.DogFoodBean {decimal: !!float '5'}\n",
+ text);
+ DogFoodBean output = (DogFoodBean) yaml.load(text);
+ assertEquals(output.getDecimal(), input.getDecimal());
+ }
+
+ public void testBigDecimalPrecision() {
+ DogFoodBean input = new DogFoodBean();
+ input.setDecimal(new BigDecimal("5.123"));
+ Yaml yaml = new Yaml();
+ String text = yaml.dump(input);
+ // System.out.println(text);
+ assertEquals("!!org.yaml.snakeyaml.issues.issue40.DogFoodBean {decimal: 5.123}\n", text);
+ DogFoodBean output = (DogFoodBean) yaml.load(text);
+ assertEquals(input.getDecimal(), output.getDecimal());
+ }
+
+ public void testBigDecimalNoRootTag() {
+ DogFoodBean input = new DogFoodBean();
+ input.setDecimal(new BigDecimal("5.123"));
+ Yaml yaml = new Yaml();
+ String text = yaml.dumpAsMap(input);
+ // System.out.println(text);
+ assertEquals("decimal: 5.123\n", text);
+ Yaml loader = new Yaml();
+ DogFoodBean output = loader.loadAs(text, DogFoodBean.class);
+ assertEquals(input.getDecimal(), output.getDecimal());
+ }
+
+ public void testBigDecimal1() {
+ Yaml yaml = new Yaml();
+ String text = yaml.dump(new BigDecimal("5"));
+ assertEquals("!!float '5'\n", text);
+ }
+
+ public void testBigDecimal2() {
+ Yaml yaml = new Yaml();
+ String text = yaml.dump(new BigDecimal("5.123"));
+ assertEquals("5.123\n", text);
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue46/FileTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue46/FileTest.java
new file mode 100644
index 0000000..f80f3ad
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue46/FileTest.java
@@ -0,0 +1,63 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue46;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.Tag;
+import org.yaml.snakeyaml.representer.Represent;
+import org.yaml.snakeyaml.representer.Representer;
+
+/**
+ * Issue 46: Dump a java.io.File object
+ */
+public class FileTest extends TestCase {
+ @SuppressWarnings("unchecked")
+ public void test() {
+ File file = new File("src/test/resources/examples/list-bean-1.yaml");
+ assertTrue(file.exists());
+ Yaml yaml = new Yaml(new MyRepresenter());
+ Map<String, File> map = new HashMap<String, File>();
+ map.put("one", file);
+ String output = yaml.dump(map);
+ // System.out.println(output);
+ assertTrue(output, output.startsWith("{one: !!java.io.File '"));
+ assertTrue(output, output.endsWith("list-bean-1.yaml'}\n"));
+ Map<String, File> parsed = (Map<String, File>) yaml.load(output);
+ File file2 = parsed.get("one");
+ assertTrue(file2.getAbsolutePath(), file2.getAbsolutePath().endsWith("list-bean-1.yaml"));
+ }
+
+ public class MyRepresenter extends Representer {
+ public MyRepresenter() {
+ this.representers.put(File.class, new FileRepresenter());
+ }
+
+ public class FileRepresenter implements Represent {
+ public Node representData(Object data) {
+ File file = (File) data;
+ Node scalar = representScalar(new Tag("!!java.io.File"), file.getAbsolutePath());
+ return scalar;
+ }
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue47/IncompleteBean.java b/src/test/java/org/yaml/snakeyaml/issues/issue47/IncompleteBean.java
new file mode 100644
index 0000000..197946f
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue47/IncompleteBean.java
@@ -0,0 +1,37 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue47;
+
+public class IncompleteBean {
+ private int id;
+ private String name;
+
+ public IncompleteBean() {
+ id = 10;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public int getId() {
+ return id;
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue47/ReadOnlyPropertiesTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue47/ReadOnlyPropertiesTest.java
new file mode 100644
index 0000000..a99f63f
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue47/ReadOnlyPropertiesTest.java
@@ -0,0 +1,59 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue47;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.error.YAMLException;
+
+public class ReadOnlyPropertiesTest extends TestCase {
+ public void testBean1() {
+ IncompleteBean bean = new IncompleteBean();
+ bean.setName("lunch");
+ Yaml yaml = new Yaml();
+ String output = yaml.dumpAsMap(bean);
+ // System.out.println(output);
+ assertEquals("name: lunch\n", output);
+ //
+ Yaml loader = new Yaml();
+ IncompleteBean parsed = loader.loadAs(output, IncompleteBean.class);
+ assertEquals(bean.getName(), parsed.getName());
+ }
+
+ public void testBean2() {
+ IncompleteBean bean = new IncompleteBean();
+ bean.setName("lunch");
+ DumperOptions options = new DumperOptions();
+ options.setAllowReadOnlyProperties(true);
+ Yaml yaml = new Yaml(options);
+ String output = yaml.dumpAsMap(bean);
+ // System.out.println(output);
+ assertEquals("id: 10\nname: lunch\n", output);
+ //
+ Yaml loader = new Yaml();
+ try {
+ loader.loadAs(output, IncompleteBean.class);
+ fail("Setter is missing.");
+ } catch (YAMLException e) {
+ String message = e.getMessage();
+ assertTrue(
+ message,
+ message.contains("Unable to find property 'id' on class: org.yaml.snakeyaml.issues.issue47.IncompleteBean"));
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue48/Bean.java b/src/test/java/org/yaml/snakeyaml/issues/issue48/Bean.java
new file mode 100644
index 0000000..cd8ef8a
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue48/Bean.java
@@ -0,0 +1,55 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue48;
+
+public class Bean {
+ private int value;
+ private String name;
+
+ public Bean() {
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return toString().equals(obj.toString());
+ }
+
+ @Override
+ public int hashCode() {
+ return value;
+ }
+
+ @Override
+ public String toString() {
+ return "Bean " + String.valueOf(value);
+ }
+
+ public int getValue() {
+ return value;
+ }
+
+ public void setValue(int value) {
+ this.value = value;
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue48/SkipJavaBeanPropertyTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue48/SkipJavaBeanPropertyTest.java
new file mode 100644
index 0000000..d537454
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue48/SkipJavaBeanPropertyTest.java
@@ -0,0 +1,56 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue48;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.introspector.Property;
+import org.yaml.snakeyaml.nodes.NodeTuple;
+import org.yaml.snakeyaml.nodes.Tag;
+import org.yaml.snakeyaml.representer.Representer;
+
+public class SkipJavaBeanPropertyTest extends TestCase {
+ public void testWithNull() {
+ Bean bean = new Bean();
+ bean.setValue(3);
+ Yaml yaml = new Yaml();
+ String output = yaml.dumpAsMap(bean);
+ // System.out.println(output);
+ assertEquals("name: null\nvalue: 3\n", output);
+ }
+
+ public void testWithoutNull() {
+ Bean bean = new Bean();
+ bean.setValue(5);
+ Yaml yaml = new Yaml(new MyRepresenter());
+ String output = yaml.dumpAsMap(bean);
+ // System.out.println(output);
+ assertEquals("value: 5\n", output);
+ }
+
+ private class MyRepresenter extends Representer {
+ @Override
+ protected NodeTuple representJavaBeanProperty(Object bean, Property property, Object value,
+ Tag customTag) {
+ if (value != null) {
+ return super.representJavaBeanProperty(bean, property, value, customTag);
+ } else {
+ return null;
+ }
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue49/CalendarBean.java b/src/test/java/org/yaml/snakeyaml/issues/issue49/CalendarBean.java
new file mode 100644
index 0000000..50587eb
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue49/CalendarBean.java
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue49;
+
+import java.util.Calendar;
+
+public class CalendarBean {
+ private Calendar calendar;
+ private String name;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Calendar getCalendar() {
+ return calendar;
+ }
+
+ public void setCalendar(Calendar calendar) {
+ this.calendar = calendar;
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue49/CalendarTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue49/CalendarTest.java
new file mode 100644
index 0000000..09af4a8
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue49/CalendarTest.java
@@ -0,0 +1,123 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue49;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.TimeZone;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+
+public class CalendarTest extends TestCase {
+ /**
+ * Daylight Saving Time is not taken into account
+ */
+ public void testDumpDstIgnored() {
+ CalendarBean bean = new CalendarBean();
+ bean.setName("lunch");
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(new Date(1000000000000L));
+ cal.setTimeZone(TimeZone.getTimeZone("GMT-8:00"));
+ bean.setCalendar(cal);
+ Yaml yaml = new Yaml();
+ String output = yaml.dumpAsMap(bean);
+ // System.out.println(output);
+ assertEquals("calendar: 2001-09-08T17:46:40-8:00\nname: lunch\n", output);
+ //
+ Yaml loader = new Yaml();
+ CalendarBean parsed = loader.loadAs(output, CalendarBean.class);
+ assertEquals(bean.getCalendar(), parsed.getCalendar());
+ }
+
+ /**
+ * Daylight Saving Time is in effect on this date/time in
+ * America/Los_Angeles Daylight<br/>
+ * Saving Time is not in effect on this date/time in GMT
+ */
+ public void testDumpDstIsNotTheSame() {
+ check(1000000000000L, "America/Los_Angeles", "Must be 7 hours difference.",
+ "2001-09-08T18:46:40-7:00");
+ }
+
+ /**
+ * Daylight Saving Time is not in effect on this date/time in
+ * America/Los_Angeles Daylight<br/>
+ * Saving Time is not in effect on this date/time in GMT
+ */
+ public void testDumpDstIsTheSame() {
+ check(1266833741374L, "America/Los_Angeles", "Must be 8 hours difference.",
+ "2010-02-22T02:15:41.374-8:00");
+ }
+
+ /**
+ * Test odd time zone
+ */
+ public void testNepal() {
+ check(1266833741374L, "Asia/Katmandu", "Must be 5:45 hours difference.",
+ "2010-02-22T16:00:41.374+5:45");
+ }
+
+ public void testMoreThen10hours() {
+ check(1266833741374L, "Asia/Kamchatka", "Must be 12 hours difference.",
+ "2010-02-22T22:15:41.374+12:00");
+ }
+
+ private void check(long time, String timeZone, String warning, String etalon) {
+ CalendarBean bean = new CalendarBean();
+ bean.setName("lunch");
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(new Date(time));
+ cal.setTimeZone(TimeZone.getTimeZone(timeZone));
+ bean.setCalendar(cal);
+ Yaml yaml = new Yaml();
+ String output = yaml.dumpAsMap(bean);
+ // System.out.println(output);
+ assertEquals(warning, "calendar: " + etalon + "\nname: lunch\n", output);
+ //
+ Yaml loader = new Yaml();
+ CalendarBean parsed = loader.loadAs(output, CalendarBean.class);
+ assertFalse("TimeZone must deviate.", bean.getCalendar().equals(parsed.getCalendar()));
+ assertEquals(bean.getCalendar().getTimeInMillis(), parsed.getCalendar().getTimeInMillis());
+ }
+
+ public void testLoadBean() {
+ Yaml beanLoader = new Yaml();
+ CalendarBean bean = beanLoader.loadAs(
+ "calendar: 2001-12-14t21:59:43.10-05:00\nname: dinner", CalendarBean.class);
+ assertEquals("dinner", bean.getName());
+ Calendar calendar = bean.getCalendar();
+ assertEquals(TimeZone.getTimeZone("GMT-5:00").getOffset(calendar.getTime().getTime()),
+ calendar.getTimeZone().getOffset(calendar.getTime().getTime()));
+ //
+ Yaml yaml = new Yaml();
+ Date date = (Date) yaml.load("2001-12-14t21:59:43.10-05:00");
+ assertEquals(date, calendar.getTime());
+ }
+
+ public void testLoadWithTag() {
+ Yaml yaml = new Yaml();
+ GregorianCalendar calendar = (GregorianCalendar) yaml
+ .load("!!java.util.GregorianCalendar 2001-12-14t21:59:43.10-05:00");
+ assertEquals(TimeZone.getTimeZone("GMT-5:00").getOffset(calendar.getTime().getTime()),
+ calendar.getTimeZone().getOffset(calendar.getTime().getTime()));
+ //
+ Date date = (Date) yaml.load("2001-12-14t21:59:43.10-05:00");
+ assertEquals(date, calendar.getTime());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue50/SnakeyamlTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue50/SnakeyamlTest.java
new file mode 100644
index 0000000..b288f80
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue50/SnakeyamlTest.java
@@ -0,0 +1,75 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue50;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+
+/**
+ * test issue 50.
+ */
+public class SnakeyamlTest extends TestCase {
+ public static interface SomeBean {
+ String getAttribute1();
+
+ String getAttribute2();
+ }
+
+ /* public */static abstract class BaseSomeBean implements SomeBean {
+ private String attribute1;
+
+ public String getAttribute1() {
+ return attribute1;
+ }
+
+ public void setAttribute1(String attribute1) {
+ this.attribute1 = attribute1;
+ }
+ }
+
+ public static final class SomeBeanImpl extends BaseSomeBean {
+ private String attribute2;
+
+ public SomeBeanImpl(final String attribute1, final String attribute2) {
+ setAttribute1(attribute1);
+ setAttribute2(attribute2);
+ }
+
+ public String getAttribute2() {
+ return attribute2;
+ }
+
+ public void setAttribute2(String attribute2) {
+ this.attribute2 = attribute2;
+ }
+
+ @Override
+ public String toString() {
+ return "SomeBeanImpl";
+ }
+ }
+
+ public void testIntrospector() {
+ SomeBean someBean = new SomeBeanImpl("value1", "value2");
+ Yaml dumper = new Yaml();
+ String output = dumper.dump(someBean);
+ // System.out.println(output);
+ assertEquals(
+ "!!org.yaml.snakeyaml.issues.issue50.SnakeyamlTest$SomeBeanImpl {attribute1: value1,\n attribute2: value2}\n",
+ output);
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue51/UnicodeStyleTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue51/UnicodeStyleTest.java
new file mode 100644
index 0000000..4570665
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue51/UnicodeStyleTest.java
@@ -0,0 +1,44 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue51;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.DumperOptions.ScalarStyle;
+import org.yaml.snakeyaml.Yaml;
+
+/**
+ * @see <a
+ * href="http://code.google.com/p/snakeyaml/issues/detail?id=51">Issue</a>
+ */
+public class UnicodeStyleTest extends TestCase {
+ public void testFoldedStyle() {
+ Yaml yaml = new Yaml();
+ String output = yaml.dump("í");
+ // System.out.println(output);
+ assertEquals("í\n", output);
+ }
+
+ public void testDoubleQuotedStyle() {
+ DumperOptions options = new DumperOptions();
+ options.setDefaultScalarStyle(ScalarStyle.DOUBLE_QUOTED);
+ Yaml yaml = new Yaml(options);
+ String output = yaml.dump("í");
+ // System.out.println(output);
+ assertEquals("\"í\"\n", output);
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue52/LineBreakDooubleQuotedTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue52/LineBreakDooubleQuotedTest.java
new file mode 100644
index 0000000..8682fdd
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue52/LineBreakDooubleQuotedTest.java
@@ -0,0 +1,57 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue52;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.DumperOptions.ScalarStyle;
+import org.yaml.snakeyaml.Yaml;
+
+/**
+ * @see <a
+ * href="http://code.google.com/p/snakeyaml/issues/detail?id=52">Issue</a>
+ */
+public class LineBreakDooubleQuotedTest extends TestCase {
+ public void testDoubleQuotedStyle() {
+ DumperOptions options = new DumperOptions();
+ options.setDefaultScalarStyle(ScalarStyle.DOUBLE_QUOTED);
+ options.setWidth(20);
+ options.setIndent(4);
+ Yaml yaml = new Yaml(options);
+ String etalon = "12345678901234567890\n\n123 456";
+ String output = yaml.dump(etalon);
+ // System.out.println(output);
+ assertEquals("\"12345678901234567890\\n\\\n \\n123 456\"\n", output);
+ String parsed = (String) yaml.load(output);
+ assertEquals(etalon, parsed);
+ }
+
+ public void testDoubleQuotedStyleNoLineSplit() {
+ DumperOptions options = new DumperOptions();
+ options.setDefaultScalarStyle(ScalarStyle.DOUBLE_QUOTED);
+ options.setWidth(20);
+ options.setSplitLines(false);
+ options.setIndent(4);
+ Yaml yaml = new Yaml(options);
+ String etalon = "12345678901234567890\n\n123 456";
+ String output = yaml.dump(etalon);
+ // System.out.println(output);
+ assertEquals("\"12345678901234567890\\n\\n123 456\"\n", output);
+ String parsed = (String) yaml.load(output);
+ assertEquals(etalon, parsed);
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue55/Blog.java b/src/test/java/org/yaml/snakeyaml/issues/issue55/Blog.java
new file mode 100644
index 0000000..228b35b
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue55/Blog.java
@@ -0,0 +1,37 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue55;
+
+import java.util.LinkedList;
+import java.util.List;
+
+class Blog {
+ private List<Post> posts = new LinkedList<Post>();
+
+ public Blog() {
+ }
+
+ public void addPost(Post p) {
+ // do some business logic here
+ posts.add(p);
+ }
+
+ public List<Post> getPosts() {
+ // in production code do not return the original set but a wrapped
+ // unmodifiable set
+ return posts;
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue55/FieldListTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue55/FieldListTest.java
new file mode 100644
index 0000000..c339ef4
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue55/FieldListTest.java
@@ -0,0 +1,58 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue55;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.introspector.BeanAccess;
+
+public class FieldListTest extends TestCase {
+
+ public void testYaml() {
+ Yaml beanLoader = new Yaml();
+ beanLoader.setBeanAccess(BeanAccess.FIELD);
+ BlogField rehydrated = beanLoader.loadAs(Util.getLocalResource("issues/issue55_2.txt"),
+ BlogField.class);
+ assertEquals(4, rehydrated.getPosts().size());
+ }
+
+ public void testFailureWithoutFieldAccess() {
+ Yaml beanLoader = new Yaml();
+ try {
+ beanLoader.loadAs(Util.getLocalResource("issues/issue55_2.txt"), BlogField.class);
+ fail("Private field must not be available");
+ } catch (Exception e) {
+ assertTrue(e.getMessage().contains("Unable to find property 'posts'"));
+ }
+ }
+
+ public static class BlogField {
+ private List<Integer> posts;
+
+ public BlogField() {
+ posts = new LinkedList<Integer>();
+ }
+
+ public List<Integer> getPosts() {
+ return posts;
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue55/JavaBeanListTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue55/JavaBeanListTest.java
new file mode 100644
index 0000000..1e8966f
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue55/JavaBeanListTest.java
@@ -0,0 +1,58 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue55;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.introspector.BeanAccess;
+
+public class JavaBeanListTest extends TestCase {
+
+ public void testYaml() {
+ Yaml beanLoader = new Yaml();
+ beanLoader.setBeanAccess(BeanAccess.FIELD);
+ BlogBean rehydrated = (BlogBean) beanLoader.loadAs(
+ Util.getLocalResource("issues/issue55_2.txt"), BlogBean.class);
+ assertEquals(4, rehydrated.getPosts().size());
+ }
+
+ public void testFailureWithoutFieldAccess() {
+ Yaml beanLoader = new Yaml();
+ try {
+ beanLoader.loadAs(Util.getLocalResource("issues/issue55_2.txt"), BlogBean.class);
+ fail("Private field must not be available");
+ } catch (Exception e) {
+ assertTrue(e.getMessage().contains("Unable to find property 'posts'"));
+ }
+ }
+
+ public static class BlogBean {
+ private List<Integer> posts;
+
+ public BlogBean() {
+ posts = new LinkedList<Integer>();
+ }
+
+ public List<Integer> getPosts() {
+ return posts;
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue55/Post.java b/src/test/java/org/yaml/snakeyaml/issues/issue55/Post.java
new file mode 100644
index 0000000..d9e60cf
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue55/Post.java
@@ -0,0 +1,42 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue55;
+
+class Post {
+ private String title;
+ private String text;
+ public static String description;
+ public transient String cache;
+
+ // TODO empty constructor is required to support 2 step construction
+ protected Post() {
+ description = "I should not be dumped.";
+ cache = "Q34598723SDW234";
+ }
+
+ public Post(String title, String text) {
+ this.title = title;
+ this.text = text;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public String getText() {
+ return text;
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue55/YamlFieldAccessCollectionTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue55/YamlFieldAccessCollectionTest.java
new file mode 100644
index 0000000..64c24d4
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue55/YamlFieldAccessCollectionTest.java
@@ -0,0 +1,96 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue55;
+
+import java.util.Collection;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.introspector.BeanAccess;
+import org.yaml.snakeyaml.representer.Representer;
+
+public class YamlFieldAccessCollectionTest extends TestCase {
+
+ public void testYaml() {
+ Blog original = createTestBlog();
+ Yaml yamlDumper = constructYamlDumper();
+ String serialized = yamlDumper.dumpAsMap(original);
+ // System.out.println(serialized);
+ assertEquals(Util.getLocalResource("issues/issue55_1.txt"), serialized);
+ Yaml blogLoader = new Yaml();
+ blogLoader.setBeanAccess(BeanAccess.FIELD);
+ Blog rehydrated = blogLoader.loadAs(serialized, Blog.class);
+ checkTestBlog(rehydrated);
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testYamlWithoutConfiguration() {
+ Yaml yaml = new Yaml();
+ Map<String, Object> map = (Map<String, Object>) yaml.load(Util
+ .getLocalResource("issues/issue55_1.txt"));
+ assertEquals(1, map.size());
+ }
+
+ public void testYamlFailure() {
+ Yaml beanLoader = new Yaml();
+ try {
+ beanLoader.loadAs(Util.getLocalResource("issues/issue55_1.txt"), Blog.class);
+ fail("BeanAccess.FIELD is required.");
+ } catch (Exception e) {
+ assertTrue(e.getMessage(), e.getMessage().contains("Unable to find property 'posts'"));
+ }
+ }
+
+ public void testYamlDefaultWithFeildAccess() {
+ Yaml yaml = new Yaml();
+ yaml.setBeanAccess(BeanAccess.FIELD);
+ Blog original = createTestBlog();
+ String serialized = yaml.dump(original);
+ assertEquals(Util.getLocalResource("issues/issue55_1_rootTag.txt"), serialized);
+ Blog rehydrated = (Blog) yaml.load(serialized);
+ checkTestBlog(rehydrated);
+ }
+
+ protected Yaml constructYamlDumper() {
+ Representer representer = new Representer();
+ representer.getPropertyUtils().setBeanAccess(BeanAccess.FIELD);
+ Yaml yaml = new Yaml(representer);
+ return yaml;
+ }
+
+ protected Yaml constructYamlParser() {
+ Yaml yaml = new Yaml();
+ yaml.setBeanAccess(BeanAccess.FIELD);
+ return yaml;
+ }
+
+ protected Blog createTestBlog() {
+ Post post1 = new Post("Test", "Dummy");
+ Post post2 = new Post("Highly", "Creative");
+ Blog blog = new Blog();
+ blog.addPost(post1);
+ blog.addPost(post2);
+ return blog;
+ }
+
+ protected void checkTestBlog(Blog blog) {
+ Collection<Post> posts = blog.getPosts();
+ assertEquals("Blog contains 2 posts", 2, posts.size());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue56/CodeBean.java b/src/test/java/org/yaml/snakeyaml/issues/issue56/CodeBean.java
new file mode 100644
index 0000000..0004363
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue56/CodeBean.java
@@ -0,0 +1,56 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue56;
+
+public class CodeBean {
+ private String country;
+ private String type;
+ private String value;
+ public static int counter;
+
+ public CodeBean() {
+ counter++;
+ }
+
+ public String getCountry() {
+ return country;
+ }
+
+ public void setCountry(String country) {
+ this.country = country;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public void setValue(String value) {
+ this.value = value;
+ }
+
+ @Override
+ public String toString() {
+ return "CodeBean: " + getValue();
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue56/PerlTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue56/PerlTest.java
new file mode 100644
index 0000000..1f04b84
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue56/PerlTest.java
@@ -0,0 +1,126 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue56;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.TypeDescription;
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.Construct;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.constructor.SafeConstructor;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.Tag;
+
+public class PerlTest extends TestCase {
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ public void testMaps() {
+ Yaml yaml = new Yaml(new CustomConstructor());
+ String input = Util.getLocalResource("issues/issue56-1.yaml");
+ int counter = 0;
+ for (Object obj : yaml.loadAll(input)) {
+ // System.out.println(obj);
+ Map<String, Object> map = (Map<String, Object>) obj;
+ Integer oid = (Integer) map.get("oid");
+ if (oid == 123058) {
+ ArrayList a = (ArrayList) map.get("sequences");
+ LinkedHashMap b = (LinkedHashMap) a.get(0);
+ LinkedHashMap c = (LinkedHashMap) b.get("atc");
+ LinkedHashMap d = (LinkedHashMap) c.get("name");
+ LinkedHashMap e = (LinkedHashMap) d.get("canonical");
+ String acidNameDe = e.entrySet().toArray()[1].toString();
+ assertEquals("Unicode escaped sequence must be decoded.",
+ ":de=Acetylsalicylsäure", acidNameDe);
+ }
+ assertTrue(oid > 10000);
+ counter++;
+ }
+ assertEquals(4, counter);
+ assertEquals(0, CodeBean.counter);
+ }
+
+ private class CustomConstructor extends SafeConstructor {
+ public CustomConstructor() {
+ // define tags which begin with !org.yaml.
+ String prefix = "!de.oddb.org,2007/ODDB";
+ this.yamlMultiConstructors.put(prefix, new ConstructYamlMap());
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testJavaBeanWithTypeDescription() {
+ Constructor c = new CustomBeanConstructor();
+ TypeDescription descr = new TypeDescription(CodeBean.class, new Tag(
+ "!de.oddb.org,2007/ODDB::Util::Code"));
+ c.addTypeDescription(descr);
+ Yaml yaml = new Yaml(c);
+ String input = Util.getLocalResource("issues/issue56-1.yaml");
+ int counter = 0;
+ for (Object obj : yaml.loadAll(input)) {
+ // System.out.println(obj);
+ Map<String, Object> map = (Map<String, Object>) obj;
+ Integer oid = (Integer) map.get("oid");
+ assertTrue(oid > 10000);
+ counter++;
+ }
+ assertEquals(4, counter);
+ assertEquals(55, CodeBean.counter);
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testJavaBean() {
+ Constructor c = new CustomBeanConstructor();
+ Yaml yaml = new Yaml(c);
+ String input = Util.getLocalResource("issues/issue56-1.yaml");
+ int counter = 0;
+ for (Object obj : yaml.loadAll(input)) {
+ // System.out.println(obj);
+ Map<String, Object> map = (Map<String, Object>) obj;
+ Integer oid = (Integer) map.get("oid");
+ assertTrue(oid > 10000);
+ counter++;
+ }
+ assertEquals(4, counter);
+ assertEquals(55, CodeBean.counter);
+ }
+
+ private class CustomBeanConstructor extends Constructor {
+ public CustomBeanConstructor() {
+ // define tags which begin with !org.yaml.
+ String prefix = "!de.oddb.org,2007/ODDB";
+ this.yamlMultiConstructors.put(prefix, new ConstructYamlMap());
+ }
+
+ protected Construct getConstructor(Node node) {
+ if (node.getTag().equals(new Tag("!de.oddb.org,2007/ODDB::Util::Code"))) {
+ node.setUseClassConstructor(true);
+ node.setType(CodeBean.class);
+ }
+ return super.getConstructor(node);
+ }
+ }
+
+ @Override
+ protected void setUp() {
+ CodeBean.counter = 0;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue58/NullValueDumperTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue58/NullValueDumperTest.java
new file mode 100644
index 0000000..9321c02
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue58/NullValueDumperTest.java
@@ -0,0 +1,60 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue58;
+
+import java.util.ArrayList;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+
+public class NullValueDumperTest extends TestCase {
+
+ public static class Foo {
+ private ArrayList<Object> bar = new ArrayList<Object>();
+
+ public ArrayList<Object> getBar() {
+ return bar;
+ }
+
+ public void setBar(ArrayList<Object> bar) {
+ this.bar = bar;
+ }
+ }
+
+ public void testListElement() {
+ final Foo foo = new Foo();
+ foo.bar.add(1);
+ foo.bar.add("A");
+ foo.bar.add(3.14);
+ Yaml yaml = new Yaml();
+ assertEquals("bar:\n- 1\n- A\n- 3.14\n", yaml.dumpAsMap(foo));
+ }
+
+ public void testNullListElement() {
+ final Foo foo = new Foo();
+
+ foo.bar.add(1);
+ foo.bar.add("A");
+ foo.bar.add(null);
+ foo.bar.add(3.14);
+ Yaml yaml = new Yaml();
+ assertEquals("bar:\n- 1\n- A\n- null\n- 3.14\n", yaml.dumpAsMap(foo));
+ assertEquals(
+ "!!org.yaml.snakeyaml.issues.issue58.NullValueDumperTest$Foo\nbar: [1, A, null, 3.14]\n",
+ new Yaml().dump(foo));
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue60/CustomOrderTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue60/CustomOrderTest.java
new file mode 100644
index 0000000..0942b53
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue60/CustomOrderTest.java
@@ -0,0 +1,84 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue60;
+
+import java.beans.IntrospectionException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.Set;
+import java.util.TreeSet;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.introspector.BeanAccess;
+import org.yaml.snakeyaml.introspector.Property;
+import org.yaml.snakeyaml.introspector.PropertyUtils;
+import org.yaml.snakeyaml.representer.Representer;
+
+//issue 59
+public class CustomOrderTest extends TestCase {
+
+ public void testReversedOrder() {
+ Representer repr = new Representer();
+ repr.setPropertyUtils(new ReversedPropertyUtils());
+ Yaml yaml = new Yaml(repr);
+ String output = yaml.dump(getBean());
+ // System.out.println(output);
+ assertEquals(Util.getLocalResource("issues/issue59-1.yaml"), output);
+ }
+
+ private class ReversedPropertyUtils extends PropertyUtils {
+ @Override
+ protected Set<Property> createPropertySet(Class<? extends Object> type, BeanAccess bAccess)
+ throws IntrospectionException {
+ Set<Property> result = new TreeSet<Property>(Collections.reverseOrder());
+ result.addAll(super.createPropertySet(type, bAccess));
+ return result;
+ }
+ }
+
+ public void testUnsorted() {
+ Representer repr = new Representer();
+ repr.setPropertyUtils(new UnsortedPropertyUtils());
+ Yaml yaml = new Yaml(repr);
+ String output = yaml.dump(getBean());
+ // System.out.println(output);
+ assertEquals(Util.getLocalResource("issues/issue59-2.yaml"), output);
+ }
+
+ private class UnsortedPropertyUtils extends PropertyUtils {
+ @Override
+ protected Set<Property> createPropertySet(Class<? extends Object> type, BeanAccess bAccess)
+ throws IntrospectionException {
+ Set<Property> result = new LinkedHashSet<Property>(getPropertiesMap(type,
+ BeanAccess.FIELD).values());
+ result.remove(result.iterator().next());// drop 'listInt' property
+ return result;
+ }
+ }
+
+ private SkipBean getBean() {
+ SkipBean bean = new SkipBean();
+ bean.setText("foo");
+ bean.setListDate(null);
+ bean.setListInt(Arrays.asList(new Integer[] { null, 1, 2, 3 }));
+ bean.setListStr(Arrays.asList(new String[] { "bar", null, "foo", null }));
+ return bean;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue60/SkipBean.java b/src/test/java/org/yaml/snakeyaml/issues/issue60/SkipBean.java
new file mode 100644
index 0000000..388feed
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue60/SkipBean.java
@@ -0,0 +1,90 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue60;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class SkipBean {
+
+ private List<Integer> listInt;
+ private List<String> listStr;
+ private List<Date> listDate;
+ private List<File> empty = new ArrayList<File>(0);
+ private Map<String, Integer> map = new HashMap<String, Integer>(0);
+ private String text;
+ private Integer number;
+
+ public List<Integer> getListInt() {
+ return listInt;
+ }
+
+ public void setListInt(List<Integer> listInt) {
+ this.listInt = listInt;
+ }
+
+ public List<String> getListStr() {
+ return listStr;
+ }
+
+ public void setListStr(List<String> listStr) {
+ this.listStr = listStr;
+ }
+
+ public List<Date> getListDate() {
+ return listDate;
+ }
+
+ public void setListDate(List<Date> listDate) {
+ this.listDate = listDate;
+ }
+
+ public String getText() {
+ return text;
+ }
+
+ public void setText(String text) {
+ this.text = text;
+ }
+
+ public Integer getNumber() {
+ return number;
+ }
+
+ public void setNumber(Integer number) {
+ this.number = number;
+ }
+
+ public List<File> getEmpty() {
+ return empty;
+ }
+
+ public void setEmpty(List<File> empty) {
+ this.empty = empty;
+ }
+
+ public Map<String, Integer> getMap() {
+ return map;
+ }
+
+ public void setMap(Map<String, Integer> map) {
+ this.map = map;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue60/SkipBeanTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue60/SkipBeanTest.java
new file mode 100644
index 0000000..8cb6e0e
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue60/SkipBeanTest.java
@@ -0,0 +1,98 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue60;
+
+import java.util.Arrays;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.introspector.Property;
+import org.yaml.snakeyaml.nodes.CollectionNode;
+import org.yaml.snakeyaml.nodes.MappingNode;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.NodeTuple;
+import org.yaml.snakeyaml.nodes.SequenceNode;
+import org.yaml.snakeyaml.nodes.Tag;
+import org.yaml.snakeyaml.representer.Representer;
+
+public class SkipBeanTest extends TestCase {
+
+ public void testSkipNull() {
+ Yaml yaml = new Yaml(new SkipNullRepresenter());
+ String output = yaml.dump(getBean());
+ // System.out.println(output);
+ assertEquals(Util.getLocalResource("issues/issue60-1.yaml"), output);
+ }
+
+ private class SkipNullRepresenter extends Representer {
+ @Override
+ protected NodeTuple representJavaBeanProperty(Object javaBean, Property property,
+ Object propertyValue, Tag customTag) {
+ if (propertyValue == null) {
+ return null;
+ } else {
+ return super
+ .representJavaBeanProperty(javaBean, property, propertyValue, customTag);
+ }
+ }
+ }
+
+ public void testSkipEmptyCollections() {
+ Yaml yaml = new Yaml(new SkipEmptyRepresenter());
+ String output = yaml.dump(getBean());
+ // System.out.println(output);
+ assertEquals(Util.getLocalResource("issues/issue60-2.yaml"), output);
+ }
+
+ private class SkipEmptyRepresenter extends Representer {
+ @Override
+ protected NodeTuple representJavaBeanProperty(Object javaBean, Property property,
+ Object propertyValue, Tag customTag) {
+ NodeTuple tuple = super.representJavaBeanProperty(javaBean, property, propertyValue,
+ customTag);
+ Node valueNode = tuple.getValueNode();
+ if (Tag.NULL.equals(valueNode.getTag())) {
+ return null;// skip 'null' values
+ }
+ if (valueNode instanceof CollectionNode) {
+ if (Tag.SEQ.equals(valueNode.getTag())) {
+ SequenceNode seq = (SequenceNode) valueNode;
+ if (seq.getValue().isEmpty()) {
+ return null;// skip empty lists
+ }
+ }
+ if (Tag.MAP.equals(valueNode.getTag())) {
+ MappingNode seq = (MappingNode) valueNode;
+ if (seq.getValue().isEmpty()) {
+ return null;// skip empty maps
+ }
+ }
+ }
+ return tuple;
+ }
+ }
+
+ private SkipBean getBean() {
+ SkipBean bean = new SkipBean();
+ bean.setText("foo");
+ bean.setListDate(null);
+ bean.setListInt(Arrays.asList(new Integer[] { null, 1, 2, 3 }));
+ bean.setListStr(Arrays.asList(new String[] { "bar", null, "foo", null }));
+ return bean;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue61/GenericListBeanTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue61/GenericListBeanTest.java
new file mode 100644
index 0000000..f872aae
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue61/GenericListBeanTest.java
@@ -0,0 +1,117 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue61;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+
+public class GenericListBeanTest extends TestCase {
+ @SuppressWarnings("unchecked")
+ public void testGenericList() {
+ Yaml yaml = new Yaml();
+ ListProvider<String> listProvider = new ListProvider<String>();
+ listProvider.getList().add("foo");
+ listProvider.getList().add("bar");
+ String s = yaml.dumpAsMap(listProvider);
+ // System.out.println(s);
+ assertEquals("list:\n- foo\n- bar\n", s);
+ // parse
+ Yaml loader = new Yaml();
+ ListProvider<String> listProvider2 = loader.loadAs(s, ListProvider.class);
+ assertEquals("foo", listProvider2.getList().get(0));
+ assertEquals("bar", listProvider2.getList().get(1));
+ assertEquals(listProvider, listProvider2);
+ }
+
+ @SuppressWarnings("rawtypes")
+ public void testGenericBean() {
+ Yaml yaml = new Yaml();
+ ListProvider<Bean> listProvider = new ListProvider<Bean>();
+ Bean foo = new Bean();
+ foo.setName("foo");
+ listProvider.getList().add(foo);
+ Bean bar = new Bean();
+ bar.setName("bar");
+ bar.setNumber(3);
+ listProvider.getList().add(bar);
+ String s = yaml.dumpAsMap(listProvider);
+ // System.out.println(s);
+ String etalon = Util.getLocalResource("issues/issue61-1.yaml");
+ assertEquals(etalon, s);
+ // parse
+ Yaml loader = new Yaml();
+ ListProvider listProvider2 = loader.loadAs(s, ListProvider.class);
+ Bean foo2 = (Bean) listProvider2.getList().get(0);
+ assertEquals("foo", foo2.getName());
+ assertEquals(0, foo2.getNumber());
+ Bean bar2 = (Bean) listProvider2.getList().get(1);
+ assertEquals("bar", bar2.getName());
+ assertEquals(3, bar2.getNumber());
+ }
+
+ public static class ListProvider<T> {
+ private List<T> list = new ArrayList<T>();
+
+ public List<T> getList() {
+ return list;
+ }
+
+ public void setList(List<T> list) {
+ this.list = list;
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof ListProvider) {
+ return list.equals(((ListProvider) obj).getList());
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return list.hashCode();
+ }
+ }
+
+ public static class Bean {
+ private String name;
+ private int number;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public int getNumber() {
+ return number;
+ }
+
+ public void setNumber(int number) {
+ this.number = number;
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue61/GenericMapBeanTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue61/GenericMapBeanTest.java
new file mode 100644
index 0000000..fd1eff2
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue61/GenericMapBeanTest.java
@@ -0,0 +1,118 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue61;
+
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+
+public class GenericMapBeanTest extends TestCase {
+ @SuppressWarnings("unchecked")
+ public void testGenericMap() {
+ Yaml yaml = new Yaml();
+ MapProvider<String, Integer> listProvider = new MapProvider<String, Integer>();
+ listProvider.getMap().put("foo", 17);
+ listProvider.getMap().put("bar", 19);
+ String s = yaml.dumpAsMap(listProvider);
+ // System.out.println(s);
+ assertEquals("map:\n foo: 17\n bar: 19\n", s);
+ // parse
+ Yaml loader = new Yaml();
+ MapProvider<String, Integer> listProvider2 = loader.loadAs(s, MapProvider.class);
+ assertEquals(new Integer(17), listProvider2.getMap().get("foo"));
+ assertEquals(new Integer(19), listProvider2.getMap().get("bar"));
+ assertEquals(listProvider, listProvider2);
+ }
+
+ @SuppressWarnings("rawtypes")
+ public void testGenericBean() {
+ Yaml yaml = new Yaml();
+ MapProvider<String, Bean> listProvider = new MapProvider<String, Bean>();
+ Bean foo = new Bean();
+ foo.setName("foo");
+ listProvider.getMap().put("foo", foo);
+ Bean bar = new Bean();
+ bar.setName("bar");
+ bar.setNumber(3);
+ listProvider.getMap().put("bar", bar);
+ String s = yaml.dumpAsMap(listProvider);
+ // System.out.println(s);
+ String etalon = Util.getLocalResource("issues/issue61-2.yaml");
+ assertEquals(etalon, s);
+ // parse
+ Yaml loader = new Yaml();
+ MapProvider listProvider2 = loader.loadAs(s, MapProvider.class);
+ Bean foo2 = (Bean) listProvider2.getMap().get("foo");
+ assertEquals("foo", foo2.getName());
+ assertEquals(0, foo2.getNumber());
+ Bean bar2 = (Bean) listProvider2.getMap().get("bar");
+ assertEquals("bar", bar2.getName());
+ assertEquals(3, bar2.getNumber());
+ }
+
+ public static class MapProvider<K, V> {
+ private Map<K, V> map = new LinkedHashMap<K, V>();
+
+ public Map<K, V> getMap() {
+ return map;
+ }
+
+ public void setMap(Map<K, V> map) {
+ this.map = map;
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof MapProvider) {
+ return map.equals(((MapProvider) obj).getMap());
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return map.hashCode();
+ }
+ }
+
+ public static class Bean {
+ private String name;
+ private int number;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public int getNumber() {
+ return number;
+ }
+
+ public void setNumber(int number) {
+ this.number = number;
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue64/MethodDesc.java b/src/test/java/org/yaml/snakeyaml/issues/issue64/MethodDesc.java
new file mode 100644
index 0000000..74ea7f5
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue64/MethodDesc.java
@@ -0,0 +1,47 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue64;
+
+import java.util.List;
+
+public class MethodDesc {
+ private String name;
+ private List<Class<?>> argTypes;
+
+ public MethodDesc() {
+ }
+
+ public MethodDesc(String name, List<Class<?>> argTypes) {
+ this.name = name;
+ this.argTypes = argTypes;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public List<Class<?>> getArgTypes() {
+ return argTypes;
+ }
+
+ public void setArgTypes(List<Class<?>> argTypes) {
+ this.argTypes = argTypes;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue64/ParameterizedTypeTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue64/ParameterizedTypeTest.java
new file mode 100644
index 0000000..50c7bc8
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue64/ParameterizedTypeTest.java
@@ -0,0 +1,86 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue64;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.AbstractConstruct;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.ScalarNode;
+import org.yaml.snakeyaml.nodes.Tag;
+import org.yaml.snakeyaml.representer.Represent;
+import org.yaml.snakeyaml.representer.Representer;
+
+public class ParameterizedTypeTest extends TestCase {
+
+ public void testRepresenter() {
+ Yaml yaml = new Yaml(new ClassConstructor(), new ClassRepresenter());
+
+ String methodName = "testMethod";
+ List<Class<?>> argTypes = new LinkedList<Class<?>>();
+ argTypes.add(String.class);
+ argTypes.add(Integer.class);
+ argTypes.add(Boolean.class);
+ MethodDesc methodDesc = new MethodDesc(methodName, argTypes);
+
+ String out = yaml.dump(methodDesc);
+ // System.out.println(out);
+ assertEquals(
+ "!!org.yaml.snakeyaml.issues.issue64.MethodDesc\nargTypes: [!clazz 'String', !clazz 'Integer', !clazz 'Boolean']\nname: testMethod\n",
+ out);
+ MethodDesc parsed = (MethodDesc) yaml.load(out);
+ assertEquals(methodName, parsed.getName());
+ List<Class<?>> argTypes2 = parsed.getArgTypes();
+ assertEquals(3, argTypes2.size());
+ assertEquals(argTypes, argTypes2);
+ }
+
+ static class ClassRepresenter extends Representer {
+ public ClassRepresenter() {
+ this.representers.put(Class.class, new RepresentClass());
+ }
+
+ private class RepresentClass implements Represent {
+ public Node representData(Object data) {
+ Class<?> clazz = (Class<?>) data;
+ return representScalar(new Tag("!clazz"), clazz.getSimpleName());
+ }
+ }
+ }
+
+ static class ClassConstructor extends Constructor {
+ public ClassConstructor() {
+ this.yamlConstructors.put(new Tag("!clazz"), new ConstructClass());
+ }
+
+ private class ConstructClass extends AbstractConstruct {
+
+ public Object construct(Node node) {
+ String clazz = (String) constructScalar((ScalarNode) node);
+ try {
+ return Class.forName("java.lang." + clazz);
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue67/NonAsciiCharsInClassNameTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue67/NonAsciiCharsInClassNameTest.java
new file mode 100644
index 0000000..1219173
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue67/NonAsciiCharsInClassNameTest.java
@@ -0,0 +1,110 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue67;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.nodes.Tag;
+import org.yaml.snakeyaml.representer.Representer;
+import org.yaml.snakeyaml.scanner.ScannerException;
+
+public class NonAsciiCharsInClassNameTest extends TestCase {
+ private String PREFIX = "!!org.yaml.snakeyaml.issues.issue67.NonAsciiCharsInClassNameTest$";
+
+ public void testDump() {
+ Académico obj = new Académico();
+ obj.setId(1);
+ obj.setName("Foo bar baz");
+ Yaml yaml = new Yaml();
+ String result = yaml.dump(obj);
+ assertEquals(PREFIX + "Acad%C3%A9mico {\n id: 1, name: Foo bar baz}\n", result);
+ }
+
+ public void testLoad() {
+ Yaml yaml = new Yaml();
+ Académico obj = (Académico) yaml.load(PREFIX + "Acad%C3%A9mico {id: 3, name: Foo bar}");
+ assertEquals(3, obj.getId());
+ assertEquals("Foo bar", obj.getName());
+ }
+
+ public void testLoadInvalidPattern() {
+ try {
+ Yaml yaml = new Yaml();
+ yaml.load(PREFIX + "Acad%WZ%A9mico {id: 3, name: Foo bar}");
+ fail("Illegal hex characters in escape (%) pattern must not be accepted.");
+ } catch (Exception e) {
+ assertEquals(
+ "while scanning a tag\n"
+ + " in 'string', line 1, column 1:\n"
+ + " !!org.yaml.snakeyaml.issues.issu ... \n"
+ + " ^\n"
+ + "expected URI escape sequence of 2 hexadecimal numbers, but found W(87) and Z(90)\n"
+ + " in 'string', line 1, column 71:\n"
+ + " ... nAsciiCharsInClassNameTest$Acad%WZ%A9mico {id: 3, name: Foo bar}\n"
+ + " ^\n", e.getMessage());
+ }
+ }
+
+ public static class Académico {
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ private int id;
+ private String name;
+ }
+
+ public void testDumpCustomTag() {
+ Académico obj = new Académico();
+ obj.setId(123);
+ obj.setName("Foo bar 123");
+ Representer repr = new Representer();
+ repr.addClassTag(Académico.class, new Tag("!foo"));
+ Yaml yaml = new Yaml(repr);
+ String result = yaml.dump(obj);
+ assertEquals("!foo {id: 123, name: Foo bar 123}\n", result);
+ }
+
+ public void testDumpEscapedTag() {
+ Académico obj = new Académico();
+ obj.setId(123);
+ obj.setName("Foo bar 123");
+ Representer repr = new Representer();
+ repr.addClassTag(Académico.class, new Tag("!Académico"));
+ Yaml yaml = new Yaml(repr);
+ String result = yaml.dump(obj);
+ assertEquals("!Acad%C3%A9mico {id: 123, name: Foo bar 123}\n", result);
+ }
+
+ public void testTag() {
+ Tag tag = new Tag("!java/javabean:foo.Bar");
+ assertEquals("!java/javabean:foo.Bar", tag.getValue());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue68/NonAsciiCharacterTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue68/NonAsciiCharacterTest.java
new file mode 100644
index 0000000..9915abc
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue68/NonAsciiCharacterTest.java
@@ -0,0 +1,77 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue68;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CodingErrorAction;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.YamlDocument;
+
+public class NonAsciiCharacterTest extends TestCase {
+
+ @SuppressWarnings("unchecked")
+ public void testLoad() {
+ Yaml yaml = new Yaml();
+ Map<String, Map<String, String>> obj = (Map<String, Map<String, String>>) yaml
+ .load("test.string: {en: И}");
+ assertEquals(1, obj.size());
+ assertEquals("Map: " + obj.toString(), "И", obj.get("test.string").get("en"));
+ }
+
+ public void testLoadFromFileWithWrongEncoding() {
+ try {
+ Yaml yaml = new Yaml();
+ InputStream input = new FileInputStream("src/test/resources/issues/issue68.txt");
+ CharsetDecoder decoder = Charset.forName("Cp1252").newDecoder();
+ decoder.onUnmappableCharacter(CodingErrorAction.REPORT);
+ Object text = yaml.load(new InputStreamReader(input, decoder));
+ input.close();
+ fail("Invalid UTF-8 must not be accepted: " + text.toString());
+ } catch (Exception e) {
+ assertTrue(e.getMessage().endsWith("Exception: Input length = 1"));
+ }
+ }
+
+ public void testLoadFromFile() throws UnsupportedEncodingException, FileNotFoundException {
+ Yaml yaml = new Yaml();
+ InputStream input = new FileInputStream("src/test/resources/issues/issue68.txt");
+ String text = (String) yaml.load(new InputStreamReader(input, "UTF-8"));
+ assertEquals("И жить торопится и чувствовать спешит...", text);
+ }
+
+ public void testLoadFromInputStream() throws IOException {
+ InputStream input;
+ input = YamlDocument.class.getClassLoader().getResourceAsStream("issues/issue68.txt");
+ if (input == null) {
+ throw new RuntimeException("Can not find issues/issue68.txt");
+ }
+ Yaml yaml = new Yaml();
+ String text = (String) yaml.load(input);// UTF-8 by default
+ assertEquals("И жить торопится и чувствовать спешит...", text);
+ input.close();
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue72/CollectionTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue72/CollectionTest.java
new file mode 100644
index 0000000..ca817e2
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue72/CollectionTest.java
@@ -0,0 +1,87 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue72;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+
+public class CollectionTest extends TestCase {
+
+ public void testCollectionList() {
+ CollectionList bean = new CollectionList();
+ Yaml yaml = new Yaml();
+ String doc = yaml.dumpAsMap(bean);
+ // System.out.println(doc);
+ Yaml beanLoader = new Yaml();
+ CollectionList parsed = beanLoader.loadAs(doc, CollectionList.class);
+ assertTrue(parsed.getNames().contains("aaa"));
+ assertTrue(parsed.getNames().contains("bbb"));
+ assertEquals(2, parsed.getNames().size());
+ }
+
+ public static class CollectionList {
+ private Collection<String> names;
+
+ public CollectionList() {
+ names = new ArrayList<String>();
+ names.add("aaa");
+ names.add("bbb");
+ }
+
+ public Collection<String> getNames() {
+ return names;
+ }
+
+ public void setNames(Collection<String> names) {
+ this.names = names;
+ }
+ }
+
+ public void testCollectionSet() {
+ CollectionSet bean = new CollectionSet();
+ Yaml yaml = new Yaml();
+ String doc = yaml.dumpAsMap(bean);
+ // System.out.println(doc);
+ Yaml beanLoader = new Yaml();
+ CollectionSet parsed = beanLoader.loadAs(doc, CollectionSet.class);
+ assertTrue(parsed.getRoles().contains(11));
+ assertTrue(parsed.getRoles().contains(13));
+ assertEquals(2, parsed.getRoles().size());
+ }
+
+ public static class CollectionSet {
+ private Collection<Integer> roles;
+
+ public CollectionSet() {
+ roles = new HashSet<Integer>();
+ roles.add(11);
+ roles.add(13);
+ }
+
+ public Collection<Integer> getRoles() {
+ return roles;
+ }
+
+ public void setRoles(Collection<Integer> roles) {
+ this.roles = roles;
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue73/ArrayListTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue73/ArrayListTest.java
new file mode 100644
index 0000000..b86c6b4
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue73/ArrayListTest.java
@@ -0,0 +1,65 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue73;
+
+import java.util.ArrayList;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+
+/**
+ * Test bean when the implementation is defined: ArrayList instead of just the
+ * interface List
+ */
+public class ArrayListTest extends TestCase {
+ public void testListImplementation() {
+ Bean1 bean = new Bean1();
+ bean.setId("ID123");
+ ArrayList<String> list = new ArrayList<String>(3);
+ list.add("zzz");
+ list.add("xxx");
+ list.add("ccc");
+ bean.setList(list);
+ Yaml yaml = new Yaml();
+ String doc = yaml.dump(bean);
+ // System.out.println(doc);
+ Bean1 loaded = (Bean1) yaml.load(doc);
+ assertEquals(3, loaded.getList().size());
+ assertEquals(ArrayList.class, loaded.getList().getClass());
+ }
+
+ public static class Bean1 {
+ private ArrayList<String> list;
+ private String id;
+
+ public ArrayList<String> getList() {
+ return list;
+ }
+
+ public void setList(ArrayList<String> list) {
+ this.list = list;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue73/Blog.java b/src/test/java/org/yaml/snakeyaml/issues/issue73/Blog.java
new file mode 100644
index 0000000..1e0be23
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue73/Blog.java
@@ -0,0 +1,79 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue73;
+
+import java.util.LinkedHashSet;
+import java.util.Set;
+import java.util.TreeSet;
+
+public class Blog {
+
+ private String name;
+ private Set<Post> posts = new TreeSet<Post>();
+ public Set<Integer> numbers = new LinkedHashSet<Integer>();
+ private TreeSet<String> labels = new TreeSet<String>();
+
+ public Blog() {
+ name = "SuperBlog";
+ }
+
+ public Blog(String name) {
+ this.name = name;
+ }
+
+ public void addPost(Post p) {
+ posts.add(p);
+ }
+
+ public Set<Post> getPosts() {
+ return posts;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public void setPosts(Set<Post> posts) {
+ this.posts = posts;
+ }
+
+ public TreeSet<String> getLabels() {
+ return labels;
+ }
+
+ public void setLabels(TreeSet<String> labels) {
+ this.labels = labels;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return name.equals(obj.toString());
+ }
+
+ @Override
+ public int hashCode() {
+ return name.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return "Blog '" + name + "'";
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue73/DumpSetAsSequenceExampleTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue73/DumpSetAsSequenceExampleTest.java
new file mode 100644
index 0000000..a656a68
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue73/DumpSetAsSequenceExampleTest.java
@@ -0,0 +1,98 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue73;
+
+import java.util.Set;
+import java.util.TreeSet;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.DumperOptions.FlowStyle;
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.introspector.BeanAccess;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.Tag;
+import org.yaml.snakeyaml.representer.Represent;
+import org.yaml.snakeyaml.representer.Representer;
+
+public class DumpSetAsSequenceExampleTest extends TestCase {
+
+ public void testDumpFlow() {
+ DumperOptions options = new DumperOptions();
+ options.setAllowReadOnlyProperties(true);
+ Yaml yaml = new Yaml(new SetRepresenter(), options);
+ String output = yaml.dump(createBlog());
+ // System.out.println(output);
+ assertEquals(Util.getLocalResource("issues/issue73-dump7.txt"), output);
+ //
+ check(output);
+ }
+
+ public void testDumpBlock() {
+ DumperOptions options = new DumperOptions();
+ options.setAllowReadOnlyProperties(true);
+ options.setDefaultFlowStyle(FlowStyle.BLOCK);
+ Yaml yaml = new Yaml(new SetRepresenter(), options);
+ String output = yaml.dump(createBlog());
+ // System.out.println(output);
+ assertEquals(Util.getLocalResource("issues/issue73-dump8.txt"), output);
+ //
+ check(output);
+ }
+
+ private class SetRepresenter extends Representer {
+ public SetRepresenter() {
+ this.multiRepresenters.put(Set.class, new RepresentIterable());
+ }
+
+ private class RepresentIterable implements Represent {
+ @SuppressWarnings("unchecked")
+ public Node representData(Object data) {
+ return representSequence(getTag(data.getClass(), Tag.SEQ), (Iterable<Object>) data,
+ null);
+
+ }
+ }
+ }
+
+ private Blog createBlog() {
+ Blog blog = new Blog("Test Me!");
+ blog.addPost(new Post("Title1", "text 1"));
+ blog.addPost(new Post("Title2", "text text 2"));
+ blog.numbers.add(19);
+ blog.numbers.add(17);
+ TreeSet<String> labels = new TreeSet<String>();
+ labels.add("Java");
+ labels.add("YAML");
+ labels.add("SnakeYAML");
+ blog.setLabels(labels);
+ return blog;
+ }
+
+ private void check(String doc) {
+ Yaml yamlLoader = new Yaml();
+ yamlLoader.setBeanAccess(BeanAccess.FIELD);
+ Blog blog = (Blog) yamlLoader.load(doc);
+ assertEquals("Test Me!", blog.getName());
+ assertEquals(2, blog.numbers.size());
+ assertEquals(2, blog.getPosts().size());
+ for (Post post : blog.getPosts()) {
+ assertEquals(Post.class, post.getClass());
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue73/Post.java b/src/test/java/org/yaml/snakeyaml/issues/issue73/Post.java
new file mode 100644
index 0000000..1739549
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue73/Post.java
@@ -0,0 +1,62 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue73;
+
+class Post implements Comparable<Post> {
+
+ private String title;
+ private String text;
+
+ protected Post() {
+ }
+
+ public Post(String title, String text) {
+ super();
+ this.title = title;
+ this.text = text;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public String getText() {
+ return text;
+ }
+
+ public int compareTo(Post o) {
+ return title.compareTo(o.title);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof Post) {
+ return toString().equals(obj.toString());
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return toString().hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return "Post " + title + " " + text;
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue73/RecursiveSetTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue73/RecursiveSetTest.java
new file mode 100644
index 0000000..ef8b01f
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue73/RecursiveSetTest.java
@@ -0,0 +1,119 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue73;
+
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+
+public class RecursiveSetTest extends TestCase {
+ public void testDumpException() {
+ Set<Object> set1 = new HashSet<Object>();
+ Set<Object> set2 = new HashSet<Object>();
+ set1.add(set2);
+ set2.add(set1);
+ Yaml yaml = new Yaml();
+ try {
+ yaml.dump(set1);
+ fail("Recursive sets are not supported.");
+ } catch (StackOverflowError e) {
+ assertEquals(null, e.getMessage());
+ }
+ }
+
+ public void testLoadException() {
+ String doc = Util.getLocalResource("issues/issue73-recursive4.txt");
+ // System.out.println(doc);
+ Yaml yaml = new Yaml();
+ try {
+ yaml.load(doc);
+ fail("Recursive sets are not supported.");
+ } catch (Exception e) {
+ assertTrue(e.getMessage(), e.getMessage().contains("Set cannot be recursive."));
+ }
+ }
+
+ /**
+ * XXX: sets can be recursive
+ */
+ @SuppressWarnings("unchecked")
+ public void testLoadRecursiveTest() {
+ String doc = Util.getLocalResource("issues/issue73-recursive5.txt");
+ // System.out.println(doc);
+ Yaml yaml = new Yaml();
+ Bean1 obj = (Bean1) yaml.load(doc);
+ Set<Object> set = obj.getSet();
+ // System.out.println(set);
+ assertEquals(LinkedHashSet.class, set.getClass());
+ assertEquals("ID123", obj.getId());
+ assertEquals(3, set.size());
+ assertTrue(set.remove("zzz"));
+ assertTrue(set.remove("ccc"));
+ assertFalse(set.contains("111"));
+ try {
+ set.contains(set);
+ fail("Recursive set fails to provide a hashcode.");
+ } catch (StackOverflowError e) {
+ // ignore
+ }
+ //
+ Set<Object> self = (Set<Object>) set.iterator().next();
+ assertEquals(LinkedHashSet.class, self.getClass());
+ assertEquals(set, self);
+ assertSame(set, self);
+ assertEquals(1, set.size());
+ assertEquals(1, self.size());
+ set.add("111");
+ assertEquals(2, set.size());
+ assertEquals(2, self.size());
+ //
+ self.clear();
+ assertTrue(self.isEmpty());
+ assertTrue(set.isEmpty());
+ assertFalse("Now it should not be recursive any longer (no StackOverflowError).",
+ set.contains(set));
+ //
+ set.add("jjj");
+ assertEquals(1, set.size());
+ assertEquals(1, self.size());
+ }
+
+ public static class Bean1 {
+ private Set<Object> set;
+ private String id;
+
+ public Set<Object> getSet() {
+ return set;
+ }
+
+ public void setSet(Set<Object> set) {
+ this.set = set;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue73/RecursiveSortedSetTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue73/RecursiveSortedSetTest.java
new file mode 100644
index 0000000..5224429
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue73/RecursiveSortedSetTest.java
@@ -0,0 +1,127 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue73;
+
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+
+public class RecursiveSortedSetTest extends TestCase {
+ public void testDumpException() {
+ SortedSet<Object> set = new TreeSet<Object>();
+ Bean11 bean = new Bean11();
+ bean.setId("ID555");
+ bean.setSet(set);
+ set.add("ggg");
+ set.add("hhh");
+ set.add(bean);
+ Yaml yaml = new Yaml();
+ String doc = yaml.dump(bean);
+ // System.out.println(doc);
+ assertEquals(Util.getLocalResource("issues/issue73-recursive9.txt"), doc);
+ }
+
+ public void testLoadException() {
+ String doc = Util.getLocalResource("issues/issue73-recursive10.txt");
+ // System.out.println(doc);
+ Yaml yaml = new Yaml();
+ try {
+ yaml.load(doc);
+ fail("Recursive sets are not supported.");
+ } catch (Exception e) {
+ assertTrue(e.getMessage(), e.getMessage().contains("Set cannot be recursive."));
+ }
+ }
+
+ /**
+ * set and JavaBean refer to each other
+ */
+ public void testLoadRecursiveTest() {
+ String doc = Util.getLocalResource("issues/issue73-recursive9.txt");
+ // System.out.println(doc);
+ Yaml yaml = new Yaml();
+ Bean11 beanWithSet = (Bean11) yaml.load(doc);
+ Set<Object> set = beanWithSet.getSet();
+ assertEquals(TreeSet.class, set.getClass());
+ assertEquals("ID555", beanWithSet.getId());
+ assertEquals(3, set.size());
+ assertTrue(set.remove("ggg"));
+ // assertFalse(set.remove("ggg"));???
+ assertTrue(set.remove("hhh"));
+ assertEquals(1, set.size());
+ //
+ Bean11 beanRef = (Bean11) set.iterator().next();
+ assertEquals(beanWithSet, beanRef);
+ assertSame(beanWithSet, beanRef);
+ //
+ assertFalse(set.isEmpty());
+ assertTrue(set.contains(beanWithSet));
+ assertFalse(set.add(beanWithSet));
+ assertTrue(set.remove(beanWithSet));
+ assertFalse(set.remove(beanWithSet));
+ assertTrue(set.isEmpty());
+ }
+
+ public static class Bean11 implements Comparable<Object> {
+ private SortedSet<Object> set;
+ private String id;
+
+ public SortedSet<Object> getSet() {
+ return set;
+ }
+
+ public void setSet(SortedSet<Object> set) {
+ this.set = set;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public int compareTo(Object o) {
+ return toString().compareTo(o.toString());
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof Bean11) {
+ Bean11 b = (Bean11) obj;
+ return id.equals(b.id);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return toString().hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return "Bean id=" + id + "set=" + System.identityHashCode(set);
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue73/SetAsSequenceTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue73/SetAsSequenceTest.java
new file mode 100644
index 0000000..7d3b4af
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue73/SetAsSequenceTest.java
@@ -0,0 +1,134 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue73;
+
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.Set;
+import java.util.TreeSet;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.introspector.BeanAccess;
+
+public class SetAsSequenceTest extends TestCase {
+
+ public void testDump() {
+ Blog blog = new Blog("Test Me!");
+ blog.addPost(new Post("Title1", "text 1"));
+ blog.addPost(new Post("Title2", "text text 2"));
+ blog.numbers.add(19);
+ blog.numbers.add(17);
+ TreeSet<String> labels = new TreeSet<String>();
+ labels.add("Java");
+ labels.add("YAML");
+ labels.add("SnakeYAML");
+ blog.setLabels(labels);
+ DumperOptions options = new DumperOptions();
+ options.setAllowReadOnlyProperties(true);
+ Yaml yaml = new Yaml(options);
+ String output = yaml.dump(blog);
+ // System.out.println(output);
+ assertEquals(Util.getLocalResource("issues/issue73-1.txt"), output);
+ }
+
+ public void testLoad() {
+ Yaml yaml = new Yaml();
+ yaml.setBeanAccess(BeanAccess.FIELD);
+ String doc = Util.getLocalResource("issues/issue73-1.txt");
+ Blog blog = (Blog) yaml.load(doc);
+ // System.out.println(blog);
+ assertEquals("Test Me!", blog.getName());
+ assertEquals(2, blog.numbers.size());
+ assertEquals(2, blog.getPosts().size());
+ for (Post post : blog.getPosts()) {
+ assertEquals(Post.class, post.getClass());
+ }
+ }
+
+ public void testYaml() {
+ String serialized = Util.getLocalResource("issues/issue73-2.txt");
+ // System.out.println(serialized);
+ Yaml beanLoader = new Yaml();
+ beanLoader.setBeanAccess(BeanAccess.FIELD);
+ Blog rehydrated = beanLoader.loadAs(serialized, Blog.class);
+ checkTestBlog(rehydrated);
+ }
+
+ protected void checkTestBlog(Blog blog) {
+ Set<Post> posts = blog.getPosts();
+ assertEquals("Blog contains 2 posts", 2, posts.size());
+ assertTrue(posts.contains(new Post("Test", "Dummy")));
+ assertTrue(posts.contains(new Post("Highly", "Creative")));
+ assertEquals("No tags!", blog.getName());
+ assertEquals(0, blog.numbers.size());
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testLoadRootSet() {
+ Yaml yaml = new Yaml();
+ String doc = Util.getLocalResource("issues/issue73-3.txt");
+ Set<String> strings = (Set<String>) yaml.load(doc);
+ // System.out.println(strings);
+ assertEquals(3, strings.size());
+ assertEquals(HashSet.class, strings.getClass());
+ assertTrue(strings.contains("aaa"));
+ assertTrue(strings.contains("bbb"));
+ assertTrue(strings.contains("ccc"));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testLoadRootSet2() {
+ Yaml yaml = new Yaml();
+ String doc = "!!java.util.HashSet {aaa: null, bbb: null, ccc: null}";
+ Set<String> strings = (Set<String>) yaml.load(doc);
+ // System.out.println(strings);
+ assertEquals(3, strings.size());
+ assertEquals(LinkedHashSet.class, strings.getClass());
+ assertTrue(strings.contains("aaa"));
+ assertTrue(strings.contains("bbb"));
+ assertTrue(strings.contains("ccc"));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testLoadRootSet3() {
+ Yaml yaml = new Yaml();
+ String doc = "!!java.util.TreeSet {aaa: null, bbb: null, ccc: null}";
+ Set<String> strings = (Set<String>) yaml.load(doc);
+ // System.out.println(strings);
+ assertEquals(3, strings.size());
+ assertEquals(TreeSet.class, strings.getClass());
+ assertTrue(strings.contains("aaa"));
+ assertTrue(strings.contains("bbb"));
+ assertTrue(strings.contains("ccc"));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testLoadRootSet6() {
+ Yaml yaml = new Yaml();
+ String doc = Util.getLocalResource("issues/issue73-6.txt");
+ Set<String> strings = (Set<String>) yaml.load(doc);
+ // System.out.println(strings);
+ assertEquals(3, strings.size());
+ assertEquals(TreeSet.class, strings.getClass());
+ assertTrue(strings.contains("aaa"));
+ assertTrue(strings.contains("bbb"));
+ assertTrue(strings.contains("ccc"));
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue73/TreeSetTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue73/TreeSetTest.java
new file mode 100644
index 0000000..7d4a3e0
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue73/TreeSetTest.java
@@ -0,0 +1,69 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue73;
+
+import java.util.TreeSet;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+
+/**
+ * Test bean when the implementation is defined: TreeSet instead of just the
+ * interface Set
+ */
+public class TreeSetTest extends TestCase {
+ public void testSetImplementation() {
+ Bean1 bean = new Bean1();
+ bean.setId("ID123");
+ TreeSet<String> list = new TreeSet<String>();
+ list.add("zzz");
+ list.add("xxx");
+ list.add("ccc");
+ bean.setSet(list);
+ Yaml yaml = new Yaml();
+ String doc = yaml.dump(bean);
+ // System.out.println(doc);
+ //
+ Bean1 loaded = (Bean1) yaml.load(doc);
+ assertEquals(3, loaded.getSet().size());
+ assertEquals(TreeSet.class, loaded.getSet().getClass());
+ assertTrue(loaded.getSet().contains("zzz"));
+ assertTrue(loaded.getSet().contains("xxx"));
+ assertTrue(loaded.getSet().contains("ccc"));
+ }
+
+ public static class Bean1 {
+ private TreeSet<String> set;
+ private String id;
+
+ public TreeSet<String> getSet() {
+ return set;
+ }
+
+ public void setSet(TreeSet<String> set) {
+ this.set = set;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue74/ArrayBeanTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue74/ArrayBeanTest.java
new file mode 100644
index 0000000..716294e
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue74/ArrayBeanTest.java
@@ -0,0 +1,150 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue74;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+
+public class ArrayBeanTest extends TestCase {
+
+ public void testArrayProperty() {
+ ArrayMember[] members = new ArrayMember[3];
+ members[0] = new ArrayMember("Foo", 21);
+ members[1] = new ArrayMember("Bar", 23);
+ members[2] = new ArrayMember("Hue Long Hair", 25);
+ ArrayBean bean = new ArrayBean();
+ bean.setId("ID123");
+ bean.setNumber(7);
+ bean.setMembers(members);
+ bean.openMembers = new ArrayMember[] { new ArrayMember("OpenFoo", 1000),
+ new ArrayMember("OpenBar", 2000) };
+ List<ArrayMember> list = new ArrayList<ArrayMember>(2);
+ list.add(new ArrayMember("John", 111));
+ list.add(new ArrayMember("Tony", 222));
+ bean.setList(list);
+ Yaml yaml = new Yaml();
+ String output = yaml.dumpAsMap(bean);
+ // System.out.println(output);
+ assertEquals(Util.getLocalResource("issues/issue74-array1.txt"), output);
+ Yaml beanLoader = new Yaml();
+ ArrayBean parsed = beanLoader.loadAs(output, ArrayBean.class);
+ // System.out.println(parsed);
+ assertEquals(3, parsed.getMembers().length);
+ assertEquals(2, parsed.openMembers.length);
+ assertEquals(2, parsed.getList().size());
+ assertEquals("ID123", parsed.getId());
+ assertEquals(7, parsed.getNumber());
+ for (ArrayMember member : parsed.getMembers()) {
+ assertTrue((member.getAge() >= 21) && (member.getAge() <= 25));
+ }
+ }
+
+ public static class ArrayBean {
+ private String id;
+ private int number;
+ private ArrayMember[] members;
+ public ArrayMember[] openMembers;
+ private List<ArrayMember> list;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public int getNumber() {
+ return number;
+ }
+
+ public void setNumber(int number) {
+ this.number = number;
+ }
+
+ public ArrayMember[] getMembers() {
+ return members;
+ }
+
+ public void setMembers(ArrayMember[] members) {
+ this.members = members;
+ }
+
+ public List<ArrayMember> getList() {
+ return list;
+ }
+
+ public void setList(List<ArrayMember> list) {
+ this.list = list;
+ }
+ }
+
+ public static class ArrayMember {
+ private String name;
+ private int age;
+
+ public ArrayMember(String name, int age) {
+ this.name = name;
+ this.age = age;
+ }
+
+ public ArrayMember() {
+ this.name = "NoName";
+ this.age = 0;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public int getAge() {
+ return age;
+ }
+
+ public void setAge(int age) {
+ this.age = age;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof ArrayMember) {
+ ArrayMember m = (ArrayMember) obj;
+ return age == m.age;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return age;
+ }
+
+ @Override
+ public String toString() {
+ return "ArrayMember age=" + age;
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue8/Person.java b/src/test/java/org/yaml/snakeyaml/issues/issue8/Person.java
new file mode 100644
index 0000000..1714a91
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue8/Person.java
@@ -0,0 +1,76 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue8;
+
+import java.io.Serializable;
+
+/**
+ * to test http://code.google.com/p/snakeyaml/issues/detail?id=8
+ */
+public class Person implements Serializable {
+ private static final long serialVersionUID = 1L;
+ private String firstName;
+ private String lastName;
+ private int hatSize;
+
+ public Person() {
+ }
+
+ public Person(String firstName, String lastName, int hatSize) {
+ this.firstName = firstName;
+ this.lastName = lastName;
+ this.hatSize = hatSize;
+ }
+
+ 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 int getHatSize() {
+ return hatSize;
+ }
+
+ public void setHatSize(int hatSize) {
+ this.hatSize = hatSize;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if (object instanceof Person) {
+ Person person = (Person) object;
+ return firstName.equals(person.firstName) && lastName.equals(person.lastName)
+ && hatSize == person.hatSize;
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return 1;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue8/PrattleRepresenterTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue8/PrattleRepresenterTest.java
new file mode 100644
index 0000000..b51ebb4
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue8/PrattleRepresenterTest.java
@@ -0,0 +1,66 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue8;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Yaml;
+
+/**
+ * to test http://code.google.com/p/snakeyaml/issues/detail?id=8
+ */
+public class PrattleRepresenterTest extends TestCase {
+ public void test() {
+ Yaml yaml = new Yaml();
+ Person person = new Person("Alan", "Gutierrez", 9);
+ String etalon = "!!org.yaml.snakeyaml.issues.issue8.Person {firstName: Alan, hatSize: 9, lastName: Gutierrez}\n";
+ assertEquals(etalon, yaml.dump(person));
+ assertEquals(etalon, yaml.dump(person));
+ }
+
+ public void test2beans() {
+ DumperOptions options = new DumperOptions();
+ options.setAllowReadOnlyProperties(true);
+ Yaml yaml = new Yaml(options);
+ Person person = new Person("Alan", "Gutierrez", 9);
+ String etalon = "!!org.yaml.snakeyaml.issues.issue8.Person {firstName: Alan, hatSize: 9, lastName: Gutierrez}\n";
+ assertEquals(etalon, yaml.dump(person));
+ Horse horse = new Horse("Tom", person);
+ String etalon2 = "!!org.yaml.snakeyaml.issues.issue8.PrattleRepresenterTest$Horse\nname: Tom\nowner: {firstName: Alan, hatSize: 9, lastName: Gutierrez}\n";
+ assertEquals(etalon2, yaml.dump(horse));
+ }
+
+ public static class Horse {
+ private String name;
+ private Person owner;
+
+ public Horse(String name, Person owner) {
+ super();
+ this.name = name;
+ this.owner = owner;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Person getOwner() {
+ return owner;
+ }
+
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue82/PropOrderInfluenceWhenAliasedInGenericCollectionTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue82/PropOrderInfluenceWhenAliasedInGenericCollectionTest.java
new file mode 100644
index 0000000..fb07b90
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue82/PropOrderInfluenceWhenAliasedInGenericCollectionTest.java
@@ -0,0 +1,320 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue82;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.TypeDescription;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.nodes.Tag;
+import org.yaml.snakeyaml.representer.Representer;
+
+/**
+ * issue 82: property order influence when aliased in generic collection
+ */
+public class PropOrderInfluenceWhenAliasedInGenericCollectionTest extends TestCase {
+
+ public static interface Account {
+ }
+
+ public static class GeneralAccount implements Account {
+ public String name = "General";
+ }
+
+ public static class SuperSaverAccount extends GeneralAccount {
+
+ public SuperSaverAccount() {
+ name = "SuperSaver";
+ }
+ }
+
+ public static class CustomerAB {
+ public Collection<Account> aAll;
+ public Collection<GeneralAccount> bGeneral;
+
+ @Override
+ public String toString() {
+ return "CustomerAB";
+ }
+ }
+
+ public static class CustomerBA {
+ public Collection<GeneralAccount> aGeneral;
+ public Collection<Account> bAll;
+ }
+
+ public static class CustomerAB_MapValue {
+ public Collection<Account> aAll;
+ public Map<String, GeneralAccount> bGeneralMap;
+
+ @Override
+ public String toString() {
+ return "CustomerAB_MapValue";
+ }
+ }
+
+ public static class CustomerAB_MapKey {
+ public Collection<Account> aAll;
+ public Map<GeneralAccount, String> bGeneralMap;
+
+ @Override
+ public String toString() {
+ return "CustomerAB_MapKey";
+ }
+ }
+
+ public static class CustomerAB_Property {
+ public Account acc;
+ public Collection<GeneralAccount> bGeneral;
+
+ @Override
+ public String toString() {
+ return "CustomerAB_Property";
+ }
+ }
+
+ public void testAB() {
+ SuperSaverAccount supersaver = new SuperSaverAccount();
+ GeneralAccount generalAccount = new GeneralAccount();
+
+ CustomerAB customerAB = new CustomerAB();
+ ArrayList<Account> all = new ArrayList<Account>();
+ all.add(supersaver);
+ all.add(generalAccount);
+ ArrayList<GeneralAccount> general = new ArrayList<GeneralAccount>();
+ general.add(generalAccount);
+ general.add(supersaver);
+
+ customerAB.aAll = all;
+ customerAB.bGeneral = general;
+
+ Yaml yaml = new Yaml();
+ String dump = yaml.dump(customerAB);
+ // System.out.println(dump);
+ CustomerAB parsed = (CustomerAB) yaml.load(dump);
+ assertNotNull(parsed);
+ }
+
+ public void testAB_Set() {
+ SuperSaverAccount supersaver = new SuperSaverAccount();
+ GeneralAccount generalAccount = new GeneralAccount();
+
+ CustomerAB customerAB = new CustomerAB();
+ ArrayList<Account> all = new ArrayList<Account>();
+ all.add(supersaver);
+ all.add(generalAccount);
+ Set<GeneralAccount> general = new HashSet<GeneralAccount>();
+ general.add(generalAccount);
+ general.add(supersaver);
+
+ customerAB.aAll = all;
+ customerAB.bGeneral = general;
+
+ Yaml yaml = new Yaml();
+ String dump = yaml.dump(customerAB);
+ // System.out.println(dump);
+ CustomerAB parsed = (CustomerAB) yaml.load(dump);
+ assertNotNull(parsed);
+ }
+
+ public void testABWithCustomTag() {
+ SuperSaverAccount supersaver = new SuperSaverAccount();
+ GeneralAccount generalAccount = new GeneralAccount();
+
+ CustomerAB customerAB = new CustomerAB();
+ ArrayList<Account> all = new ArrayList<Account>();
+ all.add(supersaver);
+ all.add(generalAccount);
+ ArrayList<GeneralAccount> general = new ArrayList<GeneralAccount>();
+ general.add(generalAccount);
+ general.add(supersaver);
+
+ customerAB.aAll = all;
+ customerAB.bGeneral = general;
+
+ Constructor constructor = new Constructor();
+ Representer representer = new Representer();
+ Tag generalAccountTag = new Tag("!GA");
+ constructor
+ .addTypeDescription(new TypeDescription(GeneralAccount.class, generalAccountTag));
+ representer.addClassTag(GeneralAccount.class, generalAccountTag);
+
+ Yaml yaml = new Yaml(constructor, representer);
+ String dump = yaml.dump(customerAB);
+ // System.out.println(dump);
+ CustomerAB parsed = (CustomerAB) yaml.load(dump);
+ assertNotNull(parsed);
+ }
+
+ public void testABProperty() {
+ SuperSaverAccount supersaver = new SuperSaverAccount();
+ GeneralAccount generalAccount = new GeneralAccount();
+
+ CustomerAB_Property customerAB_property = new CustomerAB_Property();
+ ArrayList<Account> all = new ArrayList<Account>();
+ all.add(supersaver);
+ all.add(generalAccount);
+ ArrayList<GeneralAccount> general = new ArrayList<GeneralAccount>();
+ general.add(generalAccount);
+ general.add(supersaver);
+
+ customerAB_property.acc = generalAccount;
+ customerAB_property.bGeneral = general;
+
+ Constructor constructor = new Constructor();
+ Representer representer = new Representer();
+
+ Yaml yaml = new Yaml(constructor, representer);
+ String dump = yaml.dump(customerAB_property);
+ // System.out.println(dump);
+ CustomerAB_Property parsed = (CustomerAB_Property) yaml.load(dump);
+ assertNotNull(parsed);
+ }
+
+ public void testABPropertyWithCustomTag() {
+ SuperSaverAccount supersaver = new SuperSaverAccount();
+ GeneralAccount generalAccount = new GeneralAccount();
+
+ CustomerAB_Property customerAB_property = new CustomerAB_Property();
+ ArrayList<Account> all = new ArrayList<Account>();
+ all.add(supersaver);
+ all.add(generalAccount);
+ ArrayList<GeneralAccount> general = new ArrayList<GeneralAccount>();
+ general.add(generalAccount);
+ general.add(supersaver);
+
+ customerAB_property.acc = generalAccount;
+ customerAB_property.bGeneral = general;
+
+ Constructor constructor = new Constructor();
+ Representer representer = new Representer();
+
+ Tag generalAccountTag = new Tag("!GA");
+ constructor
+ .addTypeDescription(new TypeDescription(GeneralAccount.class, generalAccountTag));
+ representer.addClassTag(GeneralAccount.class, generalAccountTag);
+
+ Yaml yaml = new Yaml(constructor, representer);
+ String dump = yaml.dump(customerAB_property);
+ // System.out.println(dump);
+ CustomerAB_Property parsed = (CustomerAB_Property) yaml.load(dump);
+ assertNotNull(parsed);
+ }
+
+ public void testABwithJavaBeanHelpers() {
+ SuperSaverAccount supersaver = new SuperSaverAccount();
+ GeneralAccount generalAccount = new GeneralAccount();
+
+ CustomerAB customerAB = new CustomerAB();
+ ArrayList<Account> all = new ArrayList<Account>();
+ all.add(supersaver);
+ all.add(generalAccount);
+ ArrayList<GeneralAccount> general = new ArrayList<GeneralAccount>();
+ general.add(generalAccount);
+ general.add(supersaver);
+
+ customerAB.aAll = all;
+ customerAB.bGeneral = general;
+
+ Yaml yaml = new Yaml();
+ String dump2 = yaml.dumpAsMap(customerAB);
+ // System.out.println(dump2);
+ Yaml loader = new Yaml();
+ CustomerAB parsed = loader.loadAs(dump2, CustomerAB.class);
+ assertNotNull(parsed);
+ }
+
+ public void testAB_asMapValue() {
+ SuperSaverAccount supersaver = new SuperSaverAccount();
+ GeneralAccount generalAccount = new GeneralAccount();
+
+ CustomerAB_MapValue customerAB_mapValue = new CustomerAB_MapValue();
+ ArrayList<Account> all = new ArrayList<Account>();
+ all.add(supersaver);
+ all.add(generalAccount);
+ Map<String, GeneralAccount> generalMap = new HashMap<String, GeneralAccount>();
+ generalMap.put(generalAccount.name, generalAccount);
+ generalMap.put(supersaver.name, supersaver);
+
+ customerAB_mapValue.aAll = all;
+ customerAB_mapValue.bGeneralMap = generalMap;
+
+ Yaml yaml = new Yaml();
+ String dump = yaml.dump(customerAB_mapValue);
+ // System.out.println(dump);
+ CustomerAB_MapValue parsed = (CustomerAB_MapValue) yaml.load(dump);
+ assertNotNull(parsed);
+ }
+
+ public void testAB_asMapKey() {
+ SuperSaverAccount supersaver = new SuperSaverAccount();
+ GeneralAccount generalAccount = new GeneralAccount();
+
+ CustomerAB_MapKey customerAB_mapKey = new CustomerAB_MapKey();
+ ArrayList<Account> all = new ArrayList<Account>();
+ all.add(supersaver);
+ all.add(generalAccount);
+ Map<GeneralAccount, String> generalMap = new HashMap<GeneralAccount, String>();
+ generalMap.put(generalAccount, generalAccount.name);
+ generalMap.put(supersaver, supersaver.name);
+
+ customerAB_mapKey.aAll = all;
+ customerAB_mapKey.bGeneralMap = generalMap;
+
+ Yaml yaml = new Yaml();
+ String dump = yaml.dump(customerAB_mapKey);
+ // System.out.println(dump);
+ CustomerAB_MapKey parsed = (CustomerAB_MapKey) yaml.load(dump);
+ assertNotNull(parsed);
+ }
+
+ public void testBA() {
+ SuperSaverAccount supersaver = new SuperSaverAccount();
+ GeneralAccount generalAccount = new GeneralAccount();
+
+ CustomerBA customerBA = new CustomerBA();
+ ArrayList<Account> all = new ArrayList<Account>();
+ all.add(supersaver);
+ all.add(generalAccount);
+ ArrayList<GeneralAccount> general = new ArrayList<GeneralAccount>();
+ general.add(generalAccount);
+ general.add(supersaver);
+
+ customerBA.aGeneral = general;
+ customerBA.bAll = all;
+
+ Yaml yaml = new Yaml();
+ String dump = yaml.dump(customerBA);
+ // System.out.println(dump);
+ //
+ CustomerBA parsed = (CustomerBA) yaml.load(dump);
+ assertEquals(2, parsed.bAll.size());
+ assertEquals(2, parsed.aGeneral.size());
+ assertFalse(parsed.bAll.equals(parsed.aGeneral));
+ GeneralAccount[] array = parsed.aGeneral.toArray(new GeneralAccount[2]);
+ assertEquals(GeneralAccount.class, array[0].getClass());
+ assertEquals(SuperSaverAccount.class, array[1].getClass());
+ assertEquals("SuperSaver", array[1].name);
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue9/Bean1.java b/src/test/java/org/yaml/snakeyaml/issues/issue9/Bean1.java
new file mode 100644
index 0000000..9d73eb4
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue9/Bean1.java
@@ -0,0 +1,58 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue9;
+
+import org.springframework.core.style.ToStringCreator;
+
+public class Bean1 implements IBean {
+
+ private String strVal = "BEAN_1";
+
+ private int intVal = 1;
+
+ public Bean1() {
+ super();
+ }
+
+ public Bean1(int intVal) {
+ this.intVal = intVal;
+ }
+
+ public String getStrVal() {
+ return strVal;
+ }
+
+ public void setStrVal(String strVal) {
+ this.strVal = strVal;
+ }
+
+ public int getIntVal() {
+ return intVal;
+ }
+
+ public void setIntVal(int intVal) {
+ this.intVal = intVal;
+ }
+
+ @Override
+ public String toString() {
+ ToStringCreator builder = new ToStringCreator(this);
+ builder.append(this.strVal);
+ builder.append(this.intVal);
+ return builder.toString();
+ }
+
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue9/Bean2.java b/src/test/java/org/yaml/snakeyaml/issues/issue9/Bean2.java
new file mode 100644
index 0000000..cc18912
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue9/Bean2.java
@@ -0,0 +1,54 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue9;
+
+import org.springframework.core.style.ToStringCreator;
+
+public class Bean2 implements IBean {
+
+ private String strVal = "BEAN_2";
+
+ private int intVal = 2;
+
+ public Bean2() {
+ super();
+ }
+
+ public String getStrVal() {
+ return strVal;
+ }
+
+ public void setStrVal(String strVal) {
+ this.strVal = strVal;
+ }
+
+ public int getIntVal() {
+ return intVal;
+ }
+
+ public void setIntVal(int intVal) {
+ this.intVal = intVal;
+ }
+
+ @Override
+ public String toString() {
+ ToStringCreator builder = new ToStringCreator(this);
+ builder.append(this.strVal);
+ builder.append(this.intVal);
+ return builder.toString();
+ }
+
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue9/BeanConstructor.java b/src/test/java/org/yaml/snakeyaml/issues/issue9/BeanConstructor.java
new file mode 100644
index 0000000..791fdc7
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue9/BeanConstructor.java
@@ -0,0 +1,60 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue9;
+
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.NodeId;
+import org.yaml.snakeyaml.nodes.ScalarNode;
+import org.yaml.snakeyaml.nodes.Tag;
+
+public class BeanConstructor extends Constructor {
+
+ public BeanConstructor() {
+ super(BeanHolder.class);
+ yamlConstructors.put(new Tag(Bean1.class), new Bean1ScalarConstructor());
+ yamlConstructors.put(new Tag(BeanHolder.class), new BeanHolderScalarConstructor());
+ }
+
+ private class Bean1ScalarConstructor extends ConstructScalar {
+ @Override
+ public Object construct(Node node) {
+ ScalarNode snode = (ScalarNode) node;
+ if (snode.getValue().length() == 0) {
+ return new Bean1();
+ } else {
+ return new Bean1(new Integer(snode.getValue()));
+ }
+ }
+ }
+
+ private class BeanHolderScalarConstructor extends ConstructScalar {
+ @Override
+ public Object construct(Node node) {
+ if (node.getNodeId() == NodeId.scalar) {
+ ScalarNode n = (ScalarNode) node;
+ String value = n.getValue();
+ int i = 3;
+ if (value.length() != 0) {
+ i = Integer.parseInt(value);
+ }
+ return new BeanHolder(new Bean1(i));
+ } else {
+ return new BeanHolder();
+ }
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue9/BeanConstructor3.java b/src/test/java/org/yaml/snakeyaml/issues/issue9/BeanConstructor3.java
new file mode 100644
index 0000000..d8984f4
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue9/BeanConstructor3.java
@@ -0,0 +1,34 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue9;
+
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.Tag;
+
+public class BeanConstructor3 extends Constructor {
+
+ public BeanConstructor3() {
+ yamlConstructors.put(new Tag(BeanHolder.class), new BeanHolderScalarConstructor());
+ }
+
+ private class BeanHolderScalarConstructor extends ConstructScalar {
+ @Override
+ public Object construct(Node node) {
+ return new BeanHolder();
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue9/BeanHolder.java b/src/test/java/org/yaml/snakeyaml/issues/issue9/BeanHolder.java
new file mode 100644
index 0000000..d274284
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue9/BeanHolder.java
@@ -0,0 +1,47 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue9;
+
+import org.springframework.core.style.ToStringCreator;
+
+public class BeanHolder {
+
+ private IBean bean = new Bean1();
+
+ public BeanHolder() {
+ super();
+ }
+
+ public BeanHolder(IBean bean) {
+ super();
+ this.bean = bean;
+ }
+
+ public IBean getBean() {
+ return bean;
+ }
+
+ public void setBean(IBean bean) {
+ this.bean = bean;
+ }
+
+ @Override
+ public String toString() {
+ ToStringCreator builder = new ToStringCreator(this);
+ builder.append(this.bean);
+ return builder.toString();
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue9/IBean.java b/src/test/java/org/yaml/snakeyaml/issues/issue9/IBean.java
new file mode 100644
index 0000000..d3c1dd6
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue9/IBean.java
@@ -0,0 +1,27 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue9;
+
+public interface IBean {
+
+ public abstract String getStrVal();
+
+ public abstract void setStrVal(String strVal);
+
+ public abstract int getIntVal();
+
+ public abstract void setIntVal(int intVal);
+}
\ No newline at end of file
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue9/NopropTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue9/NopropTest.java
new file mode 100644
index 0000000..9ee7c78
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue9/NopropTest.java
@@ -0,0 +1,150 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue9;
+
+import java.util.Iterator;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+
+public class NopropTest extends TestCase {
+
+ public void testOK01() {
+ String yaml = "--- !!org.yaml.snakeyaml.issues.issue9.BeanHolder\nbean : !!org.yaml.snakeyaml.issues.issue9.Bean1\n intVal : 11\n strVal : HALLO_1 ";
+ Iterator<Object> docs = new Yaml().loadAll(yaml).iterator();
+ assertTrue(docs.hasNext());
+ BeanHolder beanHolder = (BeanHolder) docs.next();
+ assertEquals("HALLO_1", beanHolder.getBean().getStrVal());
+ assertEquals(11, beanHolder.getBean().getIntVal());
+ }
+
+ public void testOK02() {
+ String yaml = "--- !!org.yaml.snakeyaml.issues.issue9.BeanHolder\nbean : !!org.yaml.snakeyaml.issues.issue9.Bean2\n intVal : 22\n strVal : HALLO_2 ";
+ Iterator<Object> docs = new Yaml().loadAll(yaml).iterator();
+ assertTrue(docs.hasNext());
+ BeanHolder beanHolder = (BeanHolder) docs.next();
+ assertEquals("HALLO_2", beanHolder.getBean().getStrVal());
+ assertEquals(22, beanHolder.getBean().getIntVal());
+ }
+
+ public void testOK03() {
+ String yaml = "--- !!org.yaml.snakeyaml.issues.issue9.BeanHolder\nbean : !!org.yaml.snakeyaml.issues.issue9.Bean1\n intVal : 1";
+ Iterator<Object> docs = new Yaml().loadAll(yaml).iterator();
+ assertTrue(docs.hasNext());
+ BeanHolder beanHolder = (BeanHolder) docs.next();
+ assertEquals("BEAN_1", beanHolder.getBean().getStrVal());
+ assertEquals(1, beanHolder.getBean().getIntVal());
+ }
+
+ public void testOK04() {
+ String yaml = "--- !!org.yaml.snakeyaml.issues.issue9.BeanHolder\nbean : !!org.yaml.snakeyaml.issues.issue9.Bean2\n intVal : 22";
+ Iterator<Object> docs = new Yaml().loadAll(yaml).iterator();
+ assertTrue(docs.hasNext());
+ BeanHolder beanHolder = (BeanHolder) docs.next();
+ assertEquals("BEAN_2", beanHolder.getBean().getStrVal());
+ assertEquals(22, beanHolder.getBean().getIntVal());
+ }
+
+ public void testOK05() {
+ String yaml = "--- !!org.yaml.snakeyaml.issues.issue9.BeanHolder\nbean : !!org.yaml.snakeyaml.issues.issue9.Bean1\n strVal : HALLO_1 ";
+ Iterator<Object> docs = new Yaml().loadAll(yaml).iterator();
+ assertTrue(docs.hasNext());
+ BeanHolder beanHolder = (BeanHolder) docs.next();
+ assertEquals("HALLO_1", beanHolder.getBean().getStrVal());
+ assertEquals(1, beanHolder.getBean().getIntVal());
+ }
+
+ public void testOK06() {
+ String yaml = "--- !!org.yaml.snakeyaml.issues.issue9.BeanHolder\nbean : !!org.yaml.snakeyaml.issues.issue9.Bean2\n strVal : HALLO_2 ";
+ Iterator<Object> docs = new Yaml().loadAll(yaml).iterator();
+ assertTrue(docs.hasNext());
+ BeanHolder beanHolder = (BeanHolder) docs.next();
+ assertEquals("HALLO_2", beanHolder.getBean().getStrVal());
+ assertEquals(2, beanHolder.getBean().getIntVal());
+ }
+
+ public void testEmptyBean() {
+ String yaml = "--- !!org.yaml.snakeyaml.issues.issue9.BeanHolder\nbean : !!org.yaml.snakeyaml.issues.issue9.Bean1";
+ Iterator<Object> docs = new Yaml(new BeanConstructor()).loadAll(yaml).iterator();
+ assertTrue(docs.hasNext());
+ BeanHolder beanHolder = (BeanHolder) docs.next();
+ assertEquals("BEAN_1", beanHolder.getBean().getStrVal());
+ assertEquals(1, beanHolder.getBean().getIntVal());
+ }
+
+ public void testEmptyBean2() {
+ String yaml = "--- !!org.yaml.snakeyaml.issues.issue9.BeanHolder\nbean : !!org.yaml.snakeyaml.issues.issue9.Bean1 {}";
+ Iterator<Object> docs = new Yaml().loadAll(yaml).iterator();
+ assertTrue(docs.hasNext());
+ BeanHolder beanHolder = (BeanHolder) docs.next();
+ assertEquals("BEAN_1", beanHolder.getBean().getStrVal());
+ assertEquals(1, beanHolder.getBean().getIntVal());
+ }
+
+ public void testEmptyDoc() {
+ String yaml = "--- !!org.yaml.snakeyaml.issues.issue9.BeanHolder";
+ Iterator<Object> docs = new Yaml(new BeanConstructor()).loadAll(yaml).iterator();
+ assertTrue(docs.hasNext());
+ BeanHolder beanHolder = (BeanHolder) docs.next();
+ assertEquals("BEAN_1", beanHolder.getBean().getStrVal());
+ assertEquals(3, beanHolder.getBean().getIntVal());
+ }
+
+ public void testEmptyDoc2() {
+ String yaml = "---";
+ Iterator<Object> docs = new Yaml(new BeanConstructor()).loadAll(yaml).iterator();
+ assertTrue(docs.hasNext());
+ BeanHolder beanHolder = (BeanHolder) docs.next();
+ assertNotNull(beanHolder);
+ assertEquals("BEAN_1", beanHolder.getBean().getStrVal());
+ assertEquals(3, beanHolder.getBean().getIntVal());
+ // only space is also null
+ yaml = "--- ";
+ docs = new Yaml(new BeanConstructor()).loadAll(yaml).iterator();
+ assertTrue(docs.hasNext());
+ beanHolder = (BeanHolder) docs.next();
+ assertNotNull(beanHolder);
+ assertEquals("BEAN_1", beanHolder.getBean().getStrVal());
+ assertEquals(3, beanHolder.getBean().getIntVal());
+ // only space is also null
+ yaml = "--- '23'";
+ docs = new Yaml(new BeanConstructor()).loadAll(yaml).iterator();
+ assertTrue(docs.hasNext());
+ beanHolder = (BeanHolder) docs.next();
+ assertNotNull(beanHolder);
+ assertEquals("BEAN_1", beanHolder.getBean().getStrVal());
+ assertEquals(23, beanHolder.getBean().getIntVal());
+ }
+
+ public void testEmptyDoc3() {
+ String yaml = "--- !!org.yaml.snakeyaml.issues.issue9.BeanHolder";
+ Iterator<Object> docs = new Yaml(new BeanConstructor3()).loadAll(yaml).iterator();
+ assertTrue(docs.hasNext());
+ BeanHolder beanHolder = (BeanHolder) docs.next();
+ assertEquals("BEAN_1", beanHolder.getBean().getStrVal());
+ assertEquals(1, beanHolder.getBean().getIntVal());
+ }
+
+ public void testNonBean() {
+ String yaml = "--- !!org.yaml.snakeyaml.issues.issue9.BeanHolder\nbean : !!org.yaml.snakeyaml.issues.issue9.Bean1 123";
+ Iterator<Object> docs = new Yaml().loadAll(yaml).iterator();
+ assertTrue(docs.hasNext());
+ BeanHolder beanHolder = (BeanHolder) docs.next();
+ assertEquals("BEAN_1", beanHolder.getBean().getStrVal());
+ assertEquals(123, beanHolder.getBean().getIntVal());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue94/ChangeRuntimeClassTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue94/ChangeRuntimeClassTest.java
new file mode 100644
index 0000000..b9823a0
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue94/ChangeRuntimeClassTest.java
@@ -0,0 +1,96 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue94;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.AbstractConstruct;
+import org.yaml.snakeyaml.constructor.Construct;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.nodes.Node;
+
+public class ChangeRuntimeClassTest {
+
+ @Test
+ public void testWithGlobalTag() {
+ String yamlText = "!!org.yaml.snakeyaml.issues.issue94.Entity\n" + "name: Matt\n"
+ + "nickName: Java\n";
+
+ // Now here that I would like to somehow intercept the constructor of
+ // SnakeYaml and give it
+ // an fresh instance of EntityLoadingProxy(); based on today's
+ // temperature, so to speak...
+ // that is un-preditable statically which proxy I will give it.
+
+ Yaml yaml = new Yaml(new MyConstructor());
+
+ Entity loadedEntity = null;
+ loadedEntity = (Entity) yaml.load(yamlText);
+
+ assertEquals("Matt", loadedEntity.getName());
+
+ // The expectation below is from having intercepted setNickName() with
+ // the artifical subclass and
+ // performed the calculation.
+ assertEquals("JJ-Java", loadedEntity.getNickName());
+ assertEquals(EntityLoadingProxy.class, loadedEntity.getClass());
+ }
+
+ @Test
+ public void testNoTag() {
+ String yamlText = "name: Matt\n" + "nickName: Java\n";
+ Yaml yaml = new Yaml(new MyConstructor(Entity.class));
+ Entity loadedEntity = null;
+ loadedEntity = (Entity) yaml.load(yamlText);
+ assertEquals("Matt", loadedEntity.getName());
+ assertEquals("JJ-Java", loadedEntity.getNickName());
+ }
+
+ /**
+ * @see Constructor.ConstructYamlObject
+ */
+ private class MyConstructor extends Constructor {
+ public MyConstructor() {
+ super();
+ this.yamlConstructors.put(null, new ConstructProxy());
+ }
+
+ public MyConstructor(Class<?> clazz) {
+ super(clazz);
+ this.yamlConstructors.put(null, new ConstructProxy());
+ }
+
+ private class ConstructProxy extends AbstractConstruct {
+ private Construct getConstructor(Node node) {
+ Class<?> cl = getClassForNode(node);
+ if (cl.equals(Entity.class) && true) {
+ // today's temperature is high :)
+ cl = EntityLoadingProxy.class;
+ }
+ node.setType(cl);
+ // call the constructor as if the runtime class is defined
+ Construct constructor = yamlClassConstructors.get(node.getNodeId());
+ return constructor;
+ }
+
+ public Object construct(Node node) {
+ return getConstructor(node).construct(node);
+ }
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue94/Entity.java b/src/test/java/org/yaml/snakeyaml/issues/issue94/Entity.java
new file mode 100644
index 0000000..eb3f7eb
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue94/Entity.java
@@ -0,0 +1,37 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue94;
+
+public class Entity {
+ private String name;
+ private String nickName;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getNickName() {
+ return nickName;
+ }
+
+ public void setNickName(String nickName) {
+ this.nickName = nickName;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue94/EntityLoadingProxy.java b/src/test/java/org/yaml/snakeyaml/issues/issue94/EntityLoadingProxy.java
new file mode 100644
index 0000000..e8129a1
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue94/EntityLoadingProxy.java
@@ -0,0 +1,26 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue94;
+
+public class EntityLoadingProxy extends Entity {
+
+ @Override
+ public void setNickName(String nickName) {
+ if (nickName.startsWith("J"))
+ nickName = "JJ-" + nickName;
+ super.setNickName(nickName);
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue95/ArrayInGenericCollectionTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue95/ArrayInGenericCollectionTest.java
new file mode 100644
index 0000000..b454953
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue95/ArrayInGenericCollectionTest.java
@@ -0,0 +1,152 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue95;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import junit.framework.TestCase;
+
+import org.junit.Assert;
+import org.yaml.snakeyaml.DumperOptions.FlowStyle;
+import org.yaml.snakeyaml.TypeDescription;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.introspector.BeanAccess;
+import org.yaml.snakeyaml.nodes.Tag;
+
+public class ArrayInGenericCollectionTest extends TestCase {
+
+ public static class A {
+ private Map<String, String[]> meta = new HashMap<String, String[]>();
+ }
+
+ public static class B {
+ private List<String[]> meta = new ArrayList<String[]>();
+ }
+
+ private A createA() {
+ A a = new A();
+ a.meta.put("met1", new String[] { "whatever" });
+ a.meta.put("met2", new String[] { "something", "something else" });
+ return a;
+ }
+
+ private B createB() {
+ B b = new B();
+ b.meta.add(new String[] { "whatever" });
+ b.meta.add(new String[] { "something", "something else" });
+ return b;
+ }
+
+ public void testArrayAsMapValue() {
+ Yaml yaml2dump = new Yaml();
+ yaml2dump.setBeanAccess(BeanAccess.FIELD);
+ A data = createA();
+ String dump = yaml2dump.dump(data);
+ // System.out.println(dump);
+
+ Yaml yaml2load = new Yaml();
+ yaml2load.setBeanAccess(BeanAccess.FIELD);
+ A loaded = (A) yaml2load.load(dump);
+
+ assertEquals(data.meta.size(), loaded.meta.size());
+ Set<Entry<String, String[]>> loadedMeta = loaded.meta.entrySet();
+ for (Entry<String, String[]> entry : loadedMeta) {
+ assertTrue(data.meta.containsKey(entry.getKey()));
+ Assert.assertArrayEquals(data.meta.get(entry.getKey()), entry.getValue());
+ }
+ }
+
+ public void testArrayAsMapValueWithTypeDespriptor() {
+ Yaml yaml2dump = new Yaml();
+ yaml2dump.setBeanAccess(BeanAccess.FIELD);
+ A data = createA();
+ String dump = yaml2dump.dump(data);
+ // System.out.println(dump);
+
+ TypeDescription aTypeDescr = new TypeDescription(A.class);
+ aTypeDescr.putMapPropertyType("meta", String.class, String[].class);
+
+ Constructor c = new Constructor();
+ c.addTypeDescription(aTypeDescr);
+ Yaml yaml2load = new Yaml(c);
+ yaml2load.setBeanAccess(BeanAccess.FIELD);
+
+ A loaded = (A) yaml2load.load(dump);
+
+ assertEquals(data.meta.size(), loaded.meta.size());
+ Set<Entry<String, String[]>> loadedMeta = loaded.meta.entrySet();
+ for (Entry<String, String[]> entry : loadedMeta) {
+ assertTrue(data.meta.containsKey(entry.getKey()));
+ Assert.assertArrayEquals(data.meta.get(entry.getKey()), entry.getValue());
+ }
+ }
+
+ public void testArrayAsListValue() {
+ Yaml yaml2dump = new Yaml();
+ yaml2dump.setBeanAccess(BeanAccess.FIELD);
+ B data = createB();
+ String dump = yaml2dump.dump(data);
+ // System.out.println(dump);
+
+ Yaml yaml2load = new Yaml();
+ yaml2load.setBeanAccess(BeanAccess.FIELD);
+ B loaded = (B) yaml2load.load(dump);
+
+ Assert.assertArrayEquals(data.meta.toArray(), loaded.meta.toArray());
+ }
+
+ public void testArrayAsListValueWithTypeDespriptor() {
+ Yaml yaml2dump = new Yaml();
+ yaml2dump.setBeanAccess(BeanAccess.FIELD);
+ B data = createB();
+ String dump = yaml2dump.dump(data);
+ // System.out.println(dump);
+
+ TypeDescription aTypeDescr = new TypeDescription(B.class);
+ aTypeDescr.putListPropertyType("meta", String[].class);
+
+ Constructor c = new Constructor();
+ c.addTypeDescription(aTypeDescr);
+ Yaml yaml2load = new Yaml(c);
+ yaml2load.setBeanAccess(BeanAccess.FIELD);
+
+ B loaded = (B) yaml2load.load(dump);
+
+ Assert.assertArrayEquals(data.meta.toArray(), loaded.meta.toArray());
+ }
+
+ public void testNoTags() {
+ Yaml yaml2dump = new Yaml();
+ yaml2dump.setBeanAccess(BeanAccess.FIELD);
+ B data = createB();
+ String dump = yaml2dump.dumpAs(data, Tag.MAP, FlowStyle.AUTO);
+ // System.out.println(dump);
+ assertEquals("meta:\n- [whatever]\n- [something, something else]\n", dump);
+ //
+ Constructor constr = new Constructor(B.class);
+ Yaml yaml2load = new Yaml(constr);
+ yaml2load.setBeanAccess(BeanAccess.FIELD);
+ B loaded = (B) yaml2load.load(dump);
+
+ Assert.assertArrayEquals(data.meta.toArray(), loaded.meta.toArray());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue97/Blog.java b/src/test/java/org/yaml/snakeyaml/issues/issue97/Blog.java
new file mode 100644
index 0000000..8da4dc7
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue97/Blog.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue97;
+
+import java.util.SortedSet;
+
+public class Blog {
+ private SortedSet<Post> posts;
+
+ public void addPost(Post p) {
+ posts.add(p);
+ }
+
+ public SortedSet<Post> getPosts() {
+ return posts;
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue97/Post.java b/src/test/java/org/yaml/snakeyaml/issues/issue97/Post.java
new file mode 100644
index 0000000..479055d
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue97/Post.java
@@ -0,0 +1,34 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue97;
+
+public class Post implements Comparable<Post> {
+
+ private String title;
+ private String text;
+
+ public String getTitle() {
+ return title;
+ }
+
+ public String getText() {
+ return text;
+ }
+
+ public int compareTo(Post o) {
+ return title.compareTo(o.title);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue97/YamlSortedSetTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue97/YamlSortedSetTest.java
new file mode 100644
index 0000000..1b4d3a1
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue97/YamlSortedSetTest.java
@@ -0,0 +1,79 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue97;
+
+import java.util.Collection;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.error.YAMLException;
+import org.yaml.snakeyaml.introspector.BeanAccess;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.NodeId;
+import org.yaml.snakeyaml.nodes.SequenceNode;
+
+public class YamlSortedSetTest {
+
+ @Test
+ public void testYaml() {
+ String serialized = "!!org.yaml.snakeyaml.issues.issue97.Blog\n" + "posts:\n"
+ + " - text: Dummy\n" + " title: Test\n" + " - text: Creative\n"
+ + " title: Highly\n";
+ // System.out.println(serialized);
+ Yaml yaml2 = constructYamlParser();
+ Blog rehydrated = (Blog) yaml2.load(serialized);
+ checkTestBlog(rehydrated);
+ }
+
+ protected Yaml constructYamlParser() {
+ Yaml yaml = new Yaml(new SetContructor());
+ yaml.setBeanAccess(BeanAccess.FIELD);
+ return yaml;
+ }
+
+ protected void checkTestBlog(Blog blog) {
+ Set<Post> posts = blog.getPosts();
+ Assert.assertEquals("Blog contains 2 posts", 2, posts.size());
+ }
+
+ private class SetContructor extends Constructor {
+ public SetContructor() {
+ yamlClassConstructors.put(NodeId.sequence, new ConstructSetFromSequence());
+ }
+
+ private class ConstructSetFromSequence extends ConstructSequence {
+ @Override
+ public Object construct(Node node) {
+ if (SortedSet.class.isAssignableFrom(node.getType())) {
+ if (node.isTwoStepsConstruction()) {
+ throw new YAMLException("Set cannot be recursive.");
+ } else {
+ Collection<Object> result = new TreeSet<Object>();
+ SetContructor.this.constructSequenceStep2((SequenceNode) node, result);
+ return result;
+ }
+ } else {
+ return super.construct(node);
+ }
+ }
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue99/YamlBase64Test.java b/src/test/java/org/yaml/snakeyaml/issues/issue99/YamlBase64Test.java
new file mode 100644
index 0000000..32e7eef
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue99/YamlBase64Test.java
@@ -0,0 +1,150 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue99;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.YamlDocument;
+import org.yaml.snakeyaml.constructor.AbstractConstruct;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.ScalarNode;
+import org.yaml.snakeyaml.nodes.Tag;
+
+/**
+ * Example for issue 99
+ *
+ * @see <a href="http://code.google.com/p/snakeyaml/issues/detail?id=99"></a>
+ */
+public class YamlBase64Test extends TestCase {
+
+ /**
+ * test base64 decoding
+ */
+ public void testBase64() throws IOException {
+ String text = Util.getLocalResource("issues/issue99-base64_literal.yaml");
+ String[] lines = text.split("\n");
+ String all = "";
+ for (int i = 1; i < lines.length; i++) {// skip first line
+ all = all + lines[i].trim();
+ }
+ // System.out.println(all);
+ byte[] decoded = Base64Coder.decode(all.toCharArray());
+ assertEquals(3737, decoded.length);
+ checkBytes(decoded);
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testYamlBase64Loading() throws IOException {
+ Yaml yaml = new Yaml();
+ InputStream inputStream = YamlBase64Test.class
+ .getResourceAsStream("/issues/issue99-base64_double_quoted.yaml");
+ Map<String, Object> bean = (Map<String, Object>) yaml.load(inputStream);
+ byte[] jpeg = (byte[]) bean.get("jpegPhoto");
+ checkBytes(jpeg);
+ inputStream.close();
+ }
+
+ private void checkBytes(byte[] jpeg) throws IOException {
+ InputStream input;
+ input = YamlDocument.class.getClassLoader().getResourceAsStream("issues/issue99.jpeg");
+ BufferedInputStream is = new BufferedInputStream(input);
+ int i = 0;
+ while (i < jpeg.length) {
+ int etalon = is.read();
+ if (jpeg[i] < 0) {
+ assertEquals(etalon, jpeg[i] + 256);
+ } else {
+ assertEquals(etalon, jpeg[i]);
+ }
+ i++;
+ }
+ is.close();
+ }
+
+ /**
+ * In the literal scalar all the line breaks are significant
+ *
+ * @throws IOException
+ */
+ public void testYamlBase64LoadingLiteral() throws IOException {
+ Yaml yaml = new Yaml();
+ InputStream inputStream = YamlBase64Test.class
+ .getResourceAsStream("/issues/issue99-base64_literal.yaml");
+ try {
+ yaml.load(inputStream);
+ fail("In the literal scalar all the line breaks are significant");
+ } catch (Exception e) {
+ assertEquals("Length of Base64 encoded input string is not a multiple of 4.",
+ e.getMessage());
+ } finally {
+ inputStream.close();
+ }
+ }
+
+ /**
+ * Redefine the !!binary global tag in a way that it ignores all the white
+ * spaces to be able to use literal scalar
+ */
+ @SuppressWarnings("unchecked")
+ public void testRedefineBinaryTag() throws IOException {
+ Yaml yaml = new Yaml(new SpecialContructor(Tag.BINARY));
+ InputStream inputStream = YamlBase64Test.class
+ .getResourceAsStream("/issues/issue99-base64_literal.yaml");
+ Map<String, Object> bean = (Map<String, Object>) yaml.load(inputStream);
+ byte[] jpeg = (byte[]) bean.get("jpegPhoto");
+ checkBytes(jpeg);
+ inputStream.close();
+ }
+
+ private class SpecialContructor extends Constructor {
+ public SpecialContructor(Tag tag) {
+ this.yamlConstructors.put(tag, new MyBinaryConstructor());
+ }
+
+ private class MyBinaryConstructor extends AbstractConstruct {
+ public Object construct(Node node) {
+ String contentWithNewLines = constructScalar((ScalarNode) node).toString();
+ String noNewLines = contentWithNewLines.replaceAll("\\s", "");
+ byte[] decoded = Base64Coder.decode(noNewLines.toCharArray());
+ return decoded;
+ }
+ }
+ }
+
+ /**
+ * Define a local tag to ignore all the white spaces to be able to use
+ * literal scalar
+ */
+ @SuppressWarnings("unchecked")
+ public void testLocalBinaryTag() throws IOException {
+ Yaml yaml = new Yaml(new SpecialContructor(new Tag("!beautiful")));
+ InputStream inputStream = YamlBase64Test.class
+ .getResourceAsStream("/issues/issue99-base64_literal_custom_tag.yaml");
+ Map<String, Object> bean = (Map<String, Object>) yaml.load(inputStream);
+ byte[] jpeg = (byte[]) bean.get("jpegPhoto");
+ checkBytes(jpeg);
+ inputStream.close();
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/javabeans/ConstructEmptyBeanTest.java b/src/test/java/org/yaml/snakeyaml/javabeans/ConstructEmptyBeanTest.java
new file mode 100644
index 0000000..8dea231
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/javabeans/ConstructEmptyBeanTest.java
@@ -0,0 +1,131 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.javabeans;
+
+import java.io.Serializable;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+
+public class ConstructEmptyBeanTest extends TestCase {
+ /**
+ * standard Yaml
+ */
+ public void testEmptyBean() {
+ Yaml yaml = new Yaml();
+ EmptyBean bean = (EmptyBean) yaml
+ .load("!!org.yaml.snakeyaml.javabeans.ConstructEmptyBeanTest$EmptyBean {}");
+ assertNotNull(bean);
+ assertNull(bean.getFirstName());
+ assertEquals(5, bean.getHatSize());
+ }
+
+ /**
+ * global tag is correct (but ignored)
+ */
+ public void testEmptyBean1() {
+ Yaml beanLoader = new Yaml();
+ EmptyBean bean = beanLoader.loadAs(
+ "!!org.yaml.snakeyaml.javabeans.ConstructEmptyBeanTest$EmptyBean {}",
+ EmptyBean.class);
+ assertNotNull(bean);
+ assertNull(bean.getFirstName());
+ assertEquals(5, bean.getHatSize());
+ }
+
+ /**
+ * global tag is ignored
+ */
+ public void testEmptyBean2() {
+ Yaml beanLoader = new Yaml();
+ EmptyBean bean = beanLoader.loadAs("!!Bla-bla-bla {}", EmptyBean.class);
+ assertNotNull(bean);
+ assertNull(bean.getFirstName());
+ assertEquals(5, bean.getHatSize());
+ }
+
+ /**
+ * no tag
+ */
+ public void testEmptyBean3() {
+ Yaml beanLoader = new Yaml();
+ EmptyBean bean = beanLoader.loadAs("{ }", EmptyBean.class);
+ assertNotNull(bean);
+ assertNull(bean.getFirstName());
+ assertEquals(5, bean.getHatSize());
+ }
+
+ /**
+ * empty document
+ */
+ public void testEmptyBean4() {
+ Yaml beanLoader = new Yaml();
+ EmptyBean bean = beanLoader.loadAs("", EmptyBean.class);
+ assertNull(bean);
+ }
+
+ /**
+ * local tag is ignored
+ */
+ public void testEmptyBean5() {
+ Yaml beanLoader = new Yaml();
+ EmptyBean bean = beanLoader.loadAs("!Bla-bla-bla {}", EmptyBean.class);
+ assertNotNull(bean);
+ assertNull(bean.getFirstName());
+ assertEquals(5, bean.getHatSize());
+ }
+
+ /**
+ * invalid document
+ */
+ public void testEmptyBean6() {
+ Yaml beanLoader = new Yaml();
+ try {
+ beanLoader.loadAs("{", EmptyBean.class);
+ fail("Invalid document provided.");
+ } catch (Exception e) {
+ assertEquals("while parsing a flow node\n" + " in 'string', line 1, column 2:\n"
+ + " {\n" + " ^\n" + "expected the node content, but found StreamEnd\n"
+ + " in 'string', line 1, column 2:\n" + " {\n" + " ^\n", e.getMessage());
+ }
+ }
+
+ public static class EmptyBean implements Serializable {
+ private static final long serialVersionUID = -8001155967276657180L;
+ private String firstName;
+ private int hatSize = 5;
+
+ public EmptyBean() {
+ }
+
+ public String getFirstName() {
+ return firstName;
+ }
+
+ public void setFirstName(String firstName) {
+ this.firstName = firstName;
+ }
+
+ public int getHatSize() {
+ return hatSize;
+ }
+
+ public void setHatSize(int hatSize) {
+ this.hatSize = hatSize;
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/javabeans/Door.java b/src/test/java/org/yaml/snakeyaml/javabeans/Door.java
new file mode 100644
index 0000000..7e3ad13
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/javabeans/Door.java
@@ -0,0 +1,67 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.javabeans;
+
+public class Door {
+ private String id;
+ private int height;
+
+ public Door(String id, int height) {
+ this.id = id;
+ this.height = height;
+ }
+
+ public Door() {
+ this.height = 3;
+ }
+
+ public int getHeight() {
+ return height;
+ }
+
+ public void setHeight(int height) {
+ this.height = height;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof Door) {
+ Door door = (Door) obj;
+ return id.equals(door.id);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return id.hashCode();
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ @Override
+ public String toString() {
+ return "Door id=" + id;
+ }
+
+}
diff --git a/src/test/java/org/yaml/snakeyaml/javabeans/FrontDoor.java b/src/test/java/org/yaml/snakeyaml/javabeans/FrontDoor.java
new file mode 100644
index 0000000..2b958da
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/javabeans/FrontDoor.java
@@ -0,0 +1,37 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.javabeans;
+
+public class FrontDoor extends Door {
+ private String keytype;
+
+ public FrontDoor() {
+ super();
+ }
+
+ public FrontDoor(String id, int height) {
+ super(id, height);
+ }
+
+ public String getKeytype() {
+ return keytype;
+ }
+
+ public void setKeytype(String keytype) {
+ this.keytype = keytype;
+ }
+
+}
diff --git a/src/test/java/org/yaml/snakeyaml/javabeans/House.java b/src/test/java/org/yaml/snakeyaml/javabeans/House.java
new file mode 100644
index 0000000..41ba335
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/javabeans/House.java
@@ -0,0 +1,68 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.javabeans;
+
+import java.util.List;
+import java.util.Map;
+
+public class House {
+ private String street;
+ private int number;
+ private List<Room> rooms;
+ private FrontDoor frontDoor;
+ private Map<String, String> reminders;
+
+ public String getStreet() {
+ return street;
+ }
+
+ public void setStreet(String street) {
+ this.street = street;
+ }
+
+ public int getNumber() {
+ return number;
+ }
+
+ public void setNumber(int number) {
+ this.number = number;
+ }
+
+ public List<Room> getRooms() {
+ return rooms;
+ }
+
+ public void setRooms(List<Room> rooms) {
+ this.rooms = rooms;
+ }
+
+ public FrontDoor getFrontDoor() {
+ return frontDoor;
+ }
+
+ public void setFrontDoor(FrontDoor frontDoor) {
+ this.frontDoor = frontDoor;
+ }
+
+ public Map<String, String> getReminders() {
+ return reminders;
+ }
+
+ public void setReminders(Map<String, String> reminders) {
+ this.reminders = reminders;
+ }
+
+}
diff --git a/src/test/java/org/yaml/snakeyaml/javabeans/HouseTest.java b/src/test/java/org/yaml/snakeyaml/javabeans/HouseTest.java
new file mode 100644
index 0000000..97c6933
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/javabeans/HouseTest.java
@@ -0,0 +1,144 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.javabeans;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.DumperOptions.FlowStyle;
+import org.yaml.snakeyaml.TypeDescription;
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.Constructor;
+
+public class HouseTest extends TestCase {
+ /**
+ * no root global tag
+ */
+ public void testDump1() {
+ House house = new House();
+ FrontDoor frontDoor = new FrontDoor("qaz1", 5);
+ frontDoor.setKeytype("qwerty123");
+ house.setFrontDoor(frontDoor);
+ List<Room> rooms = new ArrayList<Room>();
+ rooms.add(new Room("Hall"));
+ rooms.add(new Room("Kitchen"));
+ house.setRooms(rooms);
+ Map<String, String> reminders = new TreeMap<String, String>();
+ reminders.put("today", "do nothig");
+ reminders.put("tomorrow", "go shoping");
+ house.setReminders(reminders);
+ house.setNumber(1);
+ house.setStreet("Wall Street");
+ Yaml beanDumper = new Yaml();
+ String yaml = beanDumper.dumpAsMap(house);
+ String etalon = Util.getLocalResource("javabeans/house-dump1.yaml");
+ assertEquals(etalon, yaml);
+ // load
+ Yaml beanLoader = new Yaml();
+ House loadedHouse = beanLoader.loadAs(yaml, House.class);
+ assertNotNull(loadedHouse);
+ assertEquals("Wall Street", loadedHouse.getStreet());
+ // dump again
+ String yaml3 = beanDumper.dumpAsMap(loadedHouse);
+ assertEquals(yaml, yaml3);
+ }
+
+ /**
+ * with global root class tag (global tag should be avoided)
+ */
+ public void testDump3() {
+ House house = new House();
+ FrontDoor frontDoor = new FrontDoor("qaz1", 5);
+ frontDoor.setKeytype("qwerty123");
+ house.setFrontDoor(frontDoor);
+ List<Room> rooms = new ArrayList<Room>();
+ rooms.add(new Room("Hall"));
+ rooms.add(new Room("Kitchen"));
+ house.setRooms(rooms);
+ Map<String, String> reminders = new TreeMap<String, String>();
+ reminders.put("today", "do nothig");
+ reminders.put("tomorrow", "go shoping");
+ house.setReminders(reminders);
+ house.setNumber(1);
+ house.setStreet("Wall Street");
+ Yaml beanDumper = new Yaml();
+ String yaml = beanDumper.dumpAsMap(house);
+ String etalon = Util.getLocalResource("javabeans/house-dump3.yaml");
+ assertEquals(etalon, yaml);
+ // load
+ TypeDescription description = new TypeDescription(House.class);
+ description.putListPropertyType("rooms", Room.class);
+ Yaml beanLoader = new Yaml(new Constructor(description));
+ House loadedHouse = (House) beanLoader.load(yaml);
+ House loadedHouse2 = (House) beanLoader.loadAs(yaml, House.class);
+ assertNotNull(loadedHouse);
+ assertFalse(loadedHouse == loadedHouse2);
+ assertEquals("Wall Street", loadedHouse.getStreet());
+ assertEquals(1, loadedHouse.getNumber());
+ assertEquals(1, loadedHouse2.getNumber());
+ FrontDoor fdoor = loadedHouse.getFrontDoor();
+ assertEquals(frontDoor.getId(), fdoor.getId());
+ assertEquals(frontDoor.getHeight(), fdoor.getHeight());
+ assertEquals(frontDoor.getKeytype(), fdoor.getKeytype());
+ assertEquals(frontDoor, fdoor);
+ assertEquals(reminders, loadedHouse.getReminders());
+ List<Room> loadedRooms = loadedHouse.getRooms();
+ assertEquals(rooms, loadedRooms);
+ // dump again
+ String yaml3 = beanDumper.dumpAsMap(loadedHouse);
+ assertEquals(yaml, yaml3);
+ }
+
+ /**
+ * with global root class tag (global tag should be avoided)
+ */
+ public void testDump2() {
+ House house = new House();
+ FrontDoor frontDoor = new FrontDoor("qaz1", 5);
+ frontDoor.setKeytype("qwerty123");
+ house.setFrontDoor(frontDoor);
+ List<Room> rooms = new ArrayList<Room>();
+ rooms.add(new Room("Hall"));
+ rooms.add(new Room("Kitchen"));
+ house.setRooms(rooms);
+ Map<String, String> reminders = new TreeMap<String, String>();
+ reminders.put("today", "do nothig");
+ reminders.put("tomorrow", "go shoping");
+ house.setReminders(reminders);
+ house.setNumber(1);
+ house.setStreet("Wall Street");
+ DumperOptions options = new DumperOptions();
+ options.setDefaultFlowStyle(FlowStyle.BLOCK);
+ Yaml beanDumper = new Yaml(options);
+ String yaml = beanDumper.dump(house);
+ String etalon = Util.getLocalResource("javabeans/house-dump2.yaml");
+ assertEquals(etalon, yaml);
+ // load
+ Yaml beanLoader = new Yaml();
+ House loadedHouse = beanLoader.loadAs(yaml, House.class);
+ assertNotNull(loadedHouse);
+ assertEquals("Wall Street", loadedHouse.getStreet());
+ // dump again
+ String yaml3 = beanDumper.dump(loadedHouse);
+ assertEquals(yaml, yaml3);
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/javabeans/LongTest.java b/src/test/java/org/yaml/snakeyaml/javabeans/LongTest.java
new file mode 100644
index 0000000..7b7deaf
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/javabeans/LongTest.java
@@ -0,0 +1,73 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.javabeans;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.nodes.Tag;
+import org.yaml.snakeyaml.representer.Representer;
+
+public class LongTest extends TestCase {
+ public void testLongFail() {
+ DumperOptions options = new DumperOptions();
+ options.setDefaultScalarStyle(DumperOptions.ScalarStyle.DOUBLE_QUOTED);
+ Yaml yaml = new Yaml(options);
+ Foo foo = new Foo();
+ String output = yaml.dump(foo);
+ // System.out.println(output);
+ try {
+ yaml.load(output);
+ } catch (Exception e) {
+ assertTrue(e.getMessage(), e.getMessage().contains("argument type mismatch"));
+ }
+ }
+
+ public static class Foo {
+ private Long bar = Long.valueOf(42L);
+
+ public Long getBar() {
+ return bar;
+ }
+
+ public void setBar(Long bar) {
+ this.bar = bar;
+ }
+ }
+
+ public void testLongRepresenter() {
+ DumperOptions options = new DumperOptions();
+ options.setDefaultScalarStyle(DumperOptions.ScalarStyle.DOUBLE_QUOTED);
+ Representer repr = new Representer();
+ repr.addClassTag(Long.class, new Tag("!!java.lang.Long"));
+ Yaml yaml = new Yaml(repr, options);
+
+ Foo foo = new Foo();
+ String output = yaml.dump(foo);
+ // System.out.println(output);
+ Foo foo2 = (Foo) yaml.load(output);
+ assertEquals(new Long(42L), foo2.getBar());
+ }
+
+ public void testLongConstructor() {
+ String doc = "!!org.yaml.snakeyaml.javabeans.LongTest$Foo\n\"bar\": !!int \"42\"";
+ // System.out.println(doc);
+ Yaml yaml = new Yaml();
+ Foo foo2 = (Foo) yaml.load(doc);
+ assertEquals(new Long(42L), foo2.getBar());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/javabeans/Room.java b/src/test/java/org/yaml/snakeyaml/javabeans/Room.java
new file mode 100644
index 0000000..31e0ebd
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/javabeans/Room.java
@@ -0,0 +1,57 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.javabeans;
+
+public class Room {
+ private String name;
+
+ public Room() {
+ this.name = "Bedroom";
+ }
+
+ public Room(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof Room) {
+ Room room = (Room) obj;
+ return name.equals(room.name);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return name.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return "Room name=" + name;
+ }
+
+}
diff --git a/src/test/java/org/yaml/snakeyaml/javabeans/Shape.java b/src/test/java/org/yaml/snakeyaml/javabeans/Shape.java
new file mode 100644
index 0000000..ec086e4
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/javabeans/Shape.java
@@ -0,0 +1,21 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.javabeans;
+
+public interface Shape {
+
+ public int process();
+}
diff --git a/src/test/java/org/yaml/snakeyaml/javabeans/StringArrayTest.java b/src/test/java/org/yaml/snakeyaml/javabeans/StringArrayTest.java
new file mode 100644
index 0000000..5a38049
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/javabeans/StringArrayTest.java
@@ -0,0 +1,70 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.javabeans;
+
+import java.util.Arrays;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Yaml;
+
+public class StringArrayTest extends TestCase {
+ public void testStrings() {
+ A a = new A();
+ a.setNames(new String[] { "aaa", "bbb", "ccc" });
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(a);
+ assertEquals("!!org.yaml.snakeyaml.javabeans.StringArrayTest$A\nnames: [aaa, bbb, ccc]\n",
+ output);
+ A b = (A) yaml.load(output);
+ assertTrue(Arrays.equals(a.getNames(), b.getNames()));
+ }
+
+ public void testStringsPretty() {
+ A a = new A();
+ a.setNames(new String[] { "aaa", "bbb", "ccc" });
+ DumperOptions options = new DumperOptions();
+ options.setPrettyFlow(true);
+ Yaml yaml = new Yaml(options);
+ String output = yaml.dump(a);
+ assertEquals(
+ "!!org.yaml.snakeyaml.javabeans.StringArrayTest$A\nnames: [\n aaa,\n bbb,\n ccc]\n",
+ output);
+ A b = (A) yaml.load(output);
+ assertTrue(Arrays.equals(a.getNames(), b.getNames()));
+ }
+
+ public static class A {
+ String[] names;
+
+ public String[] getNames() {
+ return names;
+ }
+
+ public void setNames(String[] names) {
+ this.names = names;
+ }
+
+ public String getName(int index) {
+ return names[index];
+ }
+
+ public void setName(int index, String name) {
+ this.names[index] = name;
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/javabeans/Triangle.java b/src/test/java/org/yaml/snakeyaml/javabeans/Triangle.java
new file mode 100644
index 0000000..10acc6d
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/javabeans/Triangle.java
@@ -0,0 +1,32 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.javabeans;
+
+public class Triangle implements Shape {
+ private String name;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public int process() {
+ return 7;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/javabeans/TriangleBean.java b/src/test/java/org/yaml/snakeyaml/javabeans/TriangleBean.java
new file mode 100644
index 0000000..6893090
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/javabeans/TriangleBean.java
@@ -0,0 +1,42 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.javabeans;
+
+public class TriangleBean {
+ private String name;
+ private Shape shape;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Shape getShape() {
+ return shape;
+ }
+
+ public void setShape(Shape shape) {
+ this.shape = shape;
+ }
+
+ @Override
+ public String toString() {
+ return "TriangleBean name=" + name;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/javabeans/TriangleBeanTest.java b/src/test/java/org/yaml/snakeyaml/javabeans/TriangleBeanTest.java
new file mode 100644
index 0000000..8e84e75
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/javabeans/TriangleBeanTest.java
@@ -0,0 +1,69 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.javabeans;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+
+public class TriangleBeanTest extends TestCase {
+
+ public void testGetTriangle() {
+ Triangle triangle = new Triangle();
+ triangle.setName("Triangle25");
+ TriangleBean bean = new TriangleBean();
+ bean.setShape(triangle);
+ bean.setName("Bean25");
+ Yaml beanDumper = new Yaml();
+ String output = beanDumper.dumpAsMap(bean);
+ assertEquals(
+ "name: Bean25\nshape: !!org.yaml.snakeyaml.javabeans.Triangle\n name: Triangle25\n",
+ output);
+ Yaml beanLoader = new Yaml();
+ TriangleBean loadedBean = beanLoader.loadAs(output, TriangleBean.class);
+ assertNotNull(loadedBean);
+ assertEquals("Bean25", loadedBean.getName());
+ assertEquals(7, loadedBean.getShape().process());
+ }
+
+ public void testClassNotFound() {
+ String output = "name: Bean25\nshape: !!org.yaml.snakeyaml.javabeans.Triangle777\n name: Triangle25\n";
+ Yaml beanLoader = new Yaml();
+ try {
+ beanLoader.loadAs(output, TriangleBean.class);
+ fail("Class not found expected.");
+ } catch (Exception e) {
+ assertTrue(
+ e.getMessage(),
+ e.getMessage().contains(
+ "Class not found: org.yaml.snakeyaml.javabeans.Triangle777"));
+ }
+ }
+
+ /**
+ * Runtime class has less priority then an explicit tag
+ */
+ public void testClassAndTag() {
+ String output = "name: !!whatever Bean25\nshape: !!org.yaml.snakeyaml.javabeans.Triangle\n name: Triangle25\n";
+ Yaml beanLoader = new Yaml();
+ try {
+ beanLoader.loadAs(output, TriangleBean.class);
+ fail("Runtime class has less priority then an explicit tag");
+ } catch (Exception e) {
+ assertTrue(e.getMessage(), e.getMessage().contains("Class not found: whatever"));
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/json/JsonTest.java b/src/test/java/org/yaml/snakeyaml/json/JsonTest.java
new file mode 100644
index 0000000..4ba2119
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/json/JsonTest.java
@@ -0,0 +1,88 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.json;
+
+import junit.framework.TestCase;
+import org.yaml.snakeyaml.Yaml;
+
+
+import java.util.Map;
+
+public class JsonTest extends TestCase {
+
+ private Yaml loader = new Yaml();
+
+
+ public void testLooksLikeJson() {
+ Map<String, Integer> map = (Map<String, Integer>) loader.load("{a: 1}");
+ assertEquals(new Integer(1), map.get("a"));
+ }
+
+ public void testSpaceAfterColon() {
+ Map<String, Integer> map = (Map<String, Integer>) loader.load("{\"a\": 1}");
+ assertEquals(new Integer(1), map.get("a"));
+ }
+
+ public void testCounterintuitiveColon() {
+ try {
+ loader.load("{a:1}");
+ fail("We agree with libyaml and PyYAML.");
+ } catch (Exception e) {
+ assertTrue("':' in the flow context is a mess.", e.getMessage().contains("Please check http://pyyaml.org/wiki/YAMLColonInFlowContext for details."));
+ }
+ }
+
+ public void testNoSpace() {
+ Map<String, Integer> map = (Map<String, Integer>) loader.load("{\"a\":1}");
+ assertEquals(new Integer(1), map.get("a"));
+ }
+
+ public void testNoSpaceBothDoubleQuoted() {
+ Map<String, Integer> map = (Map<String, Integer>) loader.load("{\"a\":\"1\"}");
+ assertEquals("1", map.get("a"));
+ }
+
+ public void testNoSpaceSingleQouted() {
+ Map<String, Integer> map = (Map<String, Integer>) loader.load("{'a':1}");
+ assertEquals(new Integer(1), map.get("a"));
+ }
+
+ public void testManyValues() {
+ Map<String, Object> map = (Map<String, Object>) loader.load("{\"a\":1,\"b\":true,\"c\":\"foo\"}");
+ assertEquals(3, map.size());
+ assertEquals(new Integer(1), map.get("a"));
+ assertTrue((Boolean) map.get("b"));
+ assertEquals("foo", map.get("c"));
+ }
+
+ public void testConstructNull() {
+ Map<String, Object> map = (Map<String, Object>) loader.load("{a: null}");
+ assertEquals(1, map.size());
+ assertNull(map.get("a"));
+ }
+
+ public void testConstructNullFromEmpty() {
+ Map<String, Object> map = (Map<String, Object>) loader.load("{a: }");
+ assertEquals(1, map.size());
+ assertNull(map.get("a"));
+ }
+
+ public void testConstructBoolean() {
+ Map<String, Object> map = (Map<String, Object>) loader.load("{a: true}");
+ assertEquals(1, map.size());
+ assertEquals(Boolean.TRUE, map.get("a"));
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/lowlevel/LowLevelApiTest.java b/src/test/java/org/yaml/snakeyaml/lowlevel/LowLevelApiTest.java
new file mode 100644
index 0000000..12d7f3a
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/lowlevel/LowLevelApiTest.java
@@ -0,0 +1,65 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.lowlevel;
+
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.events.Event;
+import org.yaml.snakeyaml.events.ScalarEvent;
+import org.yaml.snakeyaml.nodes.Node;
+
+public class LowLevelApiTest extends TestCase {
+
+ public void testLowLevel() {
+ List<Object> list = new ArrayList<Object>();
+ list.add(1);
+ list.add("abc");
+ Map<String, String> map = new HashMap<String, String>();
+ map.put("name", "Tolstoy");
+ map.put("book", "War and People");
+ list.add(map);
+ Yaml yaml = new Yaml();
+ String etalon = yaml.dump(list);
+ // System.out.println(etalon);
+ //
+ Node node = yaml.represent(list);
+ // System.out.println(node);
+ assertEquals(
+ "Representation tree from an object and from its YAML document must be the same.",
+ yaml.compose(new StringReader(etalon)).toString(), node.toString());
+ //
+ List<Event> events = yaml.serialize(node);
+ int i = 0;
+ for (Event etalonEvent : yaml.parse(new StringReader(etalon))) {
+ Event ev1 = events.get(i++);
+ assertEquals(etalonEvent.getClass(), ev1.getClass());
+ if (etalonEvent instanceof ScalarEvent) {
+ ScalarEvent scalar1 = (ScalarEvent) etalonEvent;
+ ScalarEvent scalar2 = (ScalarEvent) ev1;
+ assertEquals(scalar1.getAnchor(), scalar2.getAnchor());
+ assertEquals(scalar1.getValue(), scalar2.getValue());
+ }
+ }
+ assertEquals(i, events.size());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/nodes/MappingNodeTest.java b/src/test/java/org/yaml/snakeyaml/nodes/MappingNodeTest.java
new file mode 100644
index 0000000..a17afbb
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/nodes/MappingNodeTest.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.nodes;
+
+import junit.framework.TestCase;
+
+public class MappingNodeTest extends TestCase {
+
+ public void testNullValue() {
+ try {
+ new MappingNode(new Tag("!tag"), true, null, null, null, false);
+ fail("Value is required.");
+ } catch (Exception e) {
+ assertEquals("value in a Node is required.", e.getMessage());
+ }
+ }
+}
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 0000000..ab7c6ca
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/nodes/NodeTest.java
@@ -0,0 +1,51 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.nodes;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.error.Mark;
+
+public class NodeTest extends TestCase {
+
+ public void testNode() {
+ try {
+ new ScalarNode(new Tag("!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(new Tag("!foo"), "Value1", null, null, '"');
+ node.setTag((Tag) null);
+ fail("Value must be required.");
+ } catch (Exception e) {
+ assertEquals("tag in a Node is required.", e.getMessage());
+ }
+ }
+
+ public void testGetEndMark() {
+ Mark mark1 = new Mark("name", 5, 2, 12, "afd asd asd", 7);
+ Mark mark2 = new Mark("name", 6, 3, 13, "afd asd asd", 8);
+ Node node = new ScalarNode(new Tag("!foo"), "bla-bla", mark1, mark2, '"');
+ assertEquals(mark1, node.getStartMark());
+ assertEquals(mark2, node.getEndMark());
+ }
+
+}
diff --git a/src/test/java/org/yaml/snakeyaml/nodes/NodeTupleTest.java b/src/test/java/org/yaml/snakeyaml/nodes/NodeTupleTest.java
new file mode 100644
index 0000000..70d0d3a
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/nodes/NodeTupleTest.java
@@ -0,0 +1,51 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.nodes;
+
+import junit.framework.TestCase;
+
+public class NodeTupleTest extends TestCase {
+
+ public void testNodeTuple1() {
+ Node node = new ScalarNode(new Tag("!tag"), "value1", null, null, null);
+ try {
+ new NodeTuple(null, node);
+ fail("Node must be provided.");
+ } catch (Exception e) {
+ assertEquals("Nodes must be provided.", e.getMessage());
+ }
+ }
+
+ public void testNodeTuple2() {
+ Node node = new ScalarNode(new Tag("!tag"), "value1", null, null, null);
+ try {
+ new NodeTuple(node, null);
+ fail("Node must be provided.");
+ } catch (Exception e) {
+ assertEquals("Nodes must be provided.", e.getMessage());
+ }
+ }
+
+ public void testToString() {
+ Node key = new ScalarNode(Tag.STR, "key1", null, null, null);
+ Node value = new ScalarNode(Tag.STR, "value1", null, null, null);
+ NodeTuple tuple = new NodeTuple(key, value);
+ assertEquals(
+ "<NodeTuple keyNode=<org.yaml.snakeyaml.nodes.ScalarNode (tag=tag:yaml.org,2002:str, value=key1)>; valueNode=<org.yaml.snakeyaml.nodes.ScalarNode (tag=tag:yaml.org,2002:str, value=value1)>>",
+ tuple.toString());
+ }
+
+}
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 0000000..501115d
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/nodes/ScalarNodeTest.java
@@ -0,0 +1,37 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+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(new Tag("str"), "text", null, null, '>');
+ assertEquals(NodeId.scalar, node.getNodeId());
+ }
+
+ public void testToString() {
+ Node node = new ScalarNode(new Tag("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 0000000..4ab1ce1
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/nodes/SequenceNodeTest.java
@@ -0,0 +1,38 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+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(new Tag("!foo"), true, new ArrayList<Node>(), null,
+ null, true);
+ assertEquals(NodeId.sequence, node.getNodeId());
+ }
+
+ public void testNullValue() {
+ try {
+ new SequenceNode(new Tag("!foo"), true, null, null, null, true);
+ fail("Value is required.");
+ } catch (Exception e) {
+ assertEquals("value in a Node is required.", e.getMessage());
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/nodes/TagTest.java b/src/test/java/org/yaml/snakeyaml/nodes/TagTest.java
new file mode 100644
index 0000000..467d335
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/nodes/TagTest.java
@@ -0,0 +1,106 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.nodes;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import junit.framework.TestCase;
+
+public class TagTest extends TestCase {
+
+ public void testCreate() {
+ try {
+ new Tag((String) null);
+ fail();
+ } catch (Exception e) {
+ assertEquals("Tag must be provided.", e.getMessage());
+ }
+ try {
+ new Tag("");
+ fail();
+ } catch (Exception e) {
+ assertEquals("Tag must not be empty.", e.getMessage());
+ }
+ try {
+ new Tag("!Dice ");
+ fail();
+ } catch (Exception e) {
+ assertEquals("Tag must not contain leading or trailing spaces.", e.getMessage());
+ }
+ Tag tag = new Tag(TagTest.class);
+ assertEquals(Tag.PREFIX + "org.yaml.snakeyaml.nodes.TagTest", tag.getValue());
+ }
+
+ public void testCreate2() {
+ try {
+ new Tag((Class<?>) null);
+ fail();
+ } catch (Exception e) {
+ assertEquals("Class for tag must be provided.", e.getMessage());
+ }
+ }
+
+ public void testGetClassName() {
+ Tag tag = new Tag(Tag.PREFIX + "org.yaml.snakeyaml.nodes.TagTest");
+ assertEquals("org.yaml.snakeyaml.nodes.TagTest", tag.getClassName());
+ }
+
+ public void testGetClassNameError() {
+ try {
+ Tag tag = new Tag("!TagTest");
+ tag.getClassName();
+ fail("Class name is only available for global tag");
+ } catch (Exception e) {
+ assertEquals("Invalid tag: !TagTest", e.getMessage());
+ }
+ }
+
+ public void testLength() {
+ String t = Tag.PREFIX + "org.yaml.snakeyaml.nodes.TagTest";
+ Tag tag = new Tag(t);
+ assertEquals(t.length(), tag.getLength());
+ }
+
+ public void testToString() {
+ Tag tag = new Tag("!car");
+ assertEquals("!car", tag.toString());
+ }
+
+ public void testUri1() {
+ Tag tag = new Tag("!Académico");
+ assertEquals("!Acad%C3%A9mico", tag.toString());
+ }
+
+ public void testUri2() {
+ Tag tag = new Tag("!ruby/object:Test::Module::Sub2");
+ assertEquals("!ruby/object:Test::Module::Sub2", tag.getValue());
+ }
+
+ public void testCompare() {
+ Tag tag = new Tag("!car");
+ assertEquals(0, tag.compareTo(new Tag("!car")));
+ }
+
+ public void testEqualsObject() {
+ Tag tag = new Tag("!car");
+ assertEquals(tag, tag);
+ assertEquals(tag, new Tag("!car"));
+ assertFalse(tag.equals(new Tag("!!str")));
+ assertFalse(tag.equals(null));
+ assertFalse(tag.equals(25));
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/nodes/TagsTest.java b/src/test/java/org/yaml/snakeyaml/nodes/TagsTest.java
new file mode 100644
index 0000000..5155623
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/nodes/TagsTest.java
@@ -0,0 +1,57 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.nodes;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Yaml;
+
+public class TagsTest extends TestCase {
+
+ public void testGetGlobalTagForClass() {
+ assertEquals(new Tag("tag:yaml.org,2002:java.lang.String"), new Tag(String.class));
+ assertEquals(new Tag("tag:yaml.org,2002:org.yaml.snakeyaml.nodes.TagsTest"), new Tag(
+ TagsTest.class));
+ }
+
+ /**
+ * test fix for issue 18 -
+ * http://code.google.com/p/snakeyaml/issues/detail?id=18
+ */
+ public void testLong() {
+ DumperOptions options = new DumperOptions();
+ options.setDefaultScalarStyle(DumperOptions.ScalarStyle.DOUBLE_QUOTED);
+ Yaml yaml = new Yaml(options);
+ Foo foo = new Foo();
+ String output = yaml.dump(foo);
+ // System.out.println(output);
+ Foo foo2 = (Foo) yaml.load(output);
+ assertEquals(new Long(42L), foo2.getBar());
+ }
+
+ public static class Foo {
+ private Long bar = Long.valueOf(42L);
+
+ public Long getBar() {
+ return bar;
+ }
+
+ public void setBar(Long bar) {
+ this.bar = bar;
+ }
+ }
+}
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 0000000..d8bd3c8
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/parser/ParserImplTest.java
@@ -0,0 +1,91 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.parser;
+
+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.ImplicitTuple;
+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.StreamReader;
+
+public class ParserImplTest extends TestCase {
+
+ private void check(LinkedList<Event> etalonEvents, Parser parser) {
+ while (parser.checkEvent(null)) {
+ Event event = parser.getEvent();
+ if (etalonEvents.isEmpty()) {
+ fail("unexpected event: " + event);
+ }
+ assertEquals(etalonEvents.removeFirst(), event);
+ }
+ assertFalse("Must contain no more events: " + parser.getEvent(), parser.checkEvent(null));
+ }
+
+ public void testGetEvent() {
+ String data = "string: abcd";
+ StreamReader reader = new StreamReader(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));
+ etalonEvents.add(new ScalarEvent(null, null, new ImplicitTuple(true, false), "string",
+ dummyMark, dummyMark, (char) 0));
+ etalonEvents.add(new ScalarEvent(null, null, new ImplicitTuple(true, false), "abcd",
+ dummyMark, dummyMark, (char) 0));
+ etalonEvents.add(new MappingEndEvent(dummyMark, dummyMark));
+ etalonEvents.add(new DocumentEndEvent(dummyMark, dummyMark, false));
+ etalonEvents.add(new StreamEndEvent(dummyMark, dummyMark));
+ check(etalonEvents, parser);
+ }
+
+ public void testGetEvent2() {
+ String data = "american:\n - Boston Red Sox";
+ StreamReader reader = new StreamReader(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));
+ etalonEvents.add(new ScalarEvent(null, null, new ImplicitTuple(true, false), "american",
+ dummyMark, dummyMark, (char) 0));
+ etalonEvents.add(new SequenceStartEvent(null, null, true, dummyMark, dummyMark,
+ Boolean.FALSE));
+ etalonEvents.add(new ScalarEvent(null, null, new ImplicitTuple(true, false),
+ "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));
+ check(etalonEvents, parser);
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/parser/VersionTagsTupleTest.java b/src/test/java/org/yaml/snakeyaml/parser/VersionTagsTupleTest.java
new file mode 100644
index 0000000..abd072b
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/parser/VersionTagsTupleTest.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.parser;
+
+import java.util.HashMap;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.DumperOptions.Version;
+
+public class VersionTagsTupleTest extends TestCase {
+
+ public void testToString() {
+ VersionTagsTuple tuple = new VersionTagsTuple(Version.V1_1, new HashMap<String, String>());
+ assertEquals("VersionTagsTuple<Version: 1.1, {}>", tuple.toString());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/partialconstruct/DeveloperBean.java b/src/test/java/org/yaml/snakeyaml/partialconstruct/DeveloperBean.java
new file mode 100644
index 0000000..f9a1e57
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/partialconstruct/DeveloperBean.java
@@ -0,0 +1,37 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.partialconstruct;
+
+public class DeveloperBean {
+ String name;
+ String language;
+
+ public String getName() {
+ return name;
+ }
+
+ public String getLanguage() {
+ return language;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public void setLanguage(String language) {
+ this.language = language;
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/org/yaml/snakeyaml/partialconstruct/FragmentComposer.java b/src/test/java/org/yaml/snakeyaml/partialconstruct/FragmentComposer.java
new file mode 100644
index 0000000..eccf57e
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/partialconstruct/FragmentComposer.java
@@ -0,0 +1,52 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.partialconstruct;
+
+import org.yaml.snakeyaml.composer.Composer;
+import org.yaml.snakeyaml.nodes.MappingNode;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.NodeTuple;
+import org.yaml.snakeyaml.nodes.ScalarNode;
+import org.yaml.snakeyaml.parser.Parser;
+import org.yaml.snakeyaml.resolver.Resolver;
+
+class FragmentComposer extends Composer {
+ String nodeName;
+
+ public FragmentComposer(Parser parser, Resolver resolver, String nodeName) {
+ super(parser, resolver);
+ this.nodeName = nodeName;
+ }
+
+ @Override
+ public Node getSingleNode() {
+ Node node = super.getSingleNode();
+ if (!MappingNode.class.isAssignableFrom(node.getClass())) {
+ throw new RuntimeException(
+ "Document is not structured as expected. Root element should be a map!");
+ }
+ MappingNode root = (MappingNode) node;
+ for (NodeTuple tuple : root.getValue()) {
+ Node keyNode = tuple.getKeyNode();
+ if (ScalarNode.class.isAssignableFrom(keyNode.getClass())) {
+ if (((ScalarNode) keyNode).getValue().equals(nodeName)) {
+ return tuple.getValueNode();
+ }
+ }
+ }
+ throw new RuntimeException("Did not find key \"" + nodeName + "\" in document-level map");
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/org/yaml/snakeyaml/partialconstruct/FragmentComposerTest.java b/src/test/java/org/yaml/snakeyaml/partialconstruct/FragmentComposerTest.java
new file mode 100644
index 0000000..c2bb990
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/partialconstruct/FragmentComposerTest.java
@@ -0,0 +1,42 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.partialconstruct;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.composer.Composer;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.parser.ParserImpl;
+import org.yaml.snakeyaml.reader.StreamReader;
+import org.yaml.snakeyaml.resolver.Resolver;
+
+public class FragmentComposerTest extends TestCase {
+
+ public void testFragment() {
+ String document = "foo: blargle\n"
+ + "developer: { name: \"Bjarne Stroustrup\", language: \"C++\"}\n"
+ + "gee: [ \"whiz\", \"bang\"]\n";//
+
+ StreamReader reader = new StreamReader(document);
+ Composer composer = new FragmentComposer(new ParserImpl(reader), new Resolver(),
+ "developer");
+ Constructor constructor = new Constructor();
+ constructor.setComposer(composer);
+ DeveloperBean developer = (DeveloperBean) constructor.getSingleData(DeveloperBean.class);
+ assertEquals("Bjarne Stroustrup", developer.name);
+ assertEquals("C++", developer.language);
+ }
+}
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 0000000..625f735
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/reader/IoReaderTest.java
@@ -0,0 +1,49 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.reader;
+
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.Reader;
+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();
+ Reader reader = new FileReader("src/test/resources/specification/example2_1.yaml");
+ List<String> list = (List<String>) yaml.load(reader);
+ reader.close();
+ assertEquals(3, list.size());
+ }
+
+ /**
+ * test input which is longer then internal buffer - 1k
+ */
+ public void testBigInput() throws IOException {
+ Yaml yaml = new Yaml();
+ Reader reader = new FileReader("src/test/resources/reader/large.yaml");
+ @SuppressWarnings("unchecked")
+ List<Object> list = (List<Object>) yaml.load(reader);
+ reader.close();
+ assertEquals(37, 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 0000000..ffde7dd
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/reader/ReaderBomTest.java
@@ -0,0 +1,116 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+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.Reader;
+import java.io.StringReader;
+import java.nio.charset.Charset;
+
+import junit.framework.TestCase;
+
+public class ReaderBomTest extends TestCase {
+
+ public void testReader() {
+ Reader input = new StringReader("test");
+ StreamReader reader = new StreamReader(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);
+ Reader r = new UnicodeReader(input);
+ StreamReader reader = new StreamReader(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);
+ StreamReader reader = new StreamReader(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());
+ input.close();
+ }
+
+ 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);
+ StreamReader reader = new StreamReader(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());
+ input.close();
+ }
+
+ 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);
+ StreamReader reader = new StreamReader(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());
+ input.close();
+ }
+}
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 0000000..282b7e6
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/reader/ReaderStringTest.java
@@ -0,0 +1,107 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.reader;
+
+import java.util.regex.Matcher;
+
+import junit.framework.TestCase;
+
+public class ReaderStringTest extends TestCase {
+
+ public void testCheckPrintable() {
+ StreamReader reader = new StreamReader("test");
+ reader.checkPrintable("test");
+ Matcher matcher = StreamReader.NON_PRINTABLE.matcher("test");
+ assertFalse(matcher.find());
+
+ try {
+ reader.checkPrintable("test".toCharArray(), 0, 4);
+ } catch (ReaderException e) {
+ fail();
+ }
+
+ }
+
+ public void testCheckNonPrintable() {
+ Matcher matcher = StreamReader.NON_PRINTABLE.matcher("test\u0005 fail");
+ assertTrue(matcher.find());
+ try {
+ new StreamReader("test\u0005 fail");
+ fail("Non printable Unicode characters must not be accepted.");
+ } catch (ReaderException e) {
+ assertEquals(
+ "unacceptable character '' (0x5) special characters are not allowed\nin \"'string'\", position 4",
+ e.toString());
+ }
+ }
+
+ /**
+ * test that regular expression and array check work the same
+ */
+ public void testCheckAll() {
+ StreamReader streamReader = new StreamReader("");
+ for (char i = 0; i < 256 * 256 - 1; i++) {
+ char[] chars = new char[1];
+ chars[0] = i;
+ String str = new String(chars);
+ Matcher matcher = StreamReader.NON_PRINTABLE.matcher(str);
+ boolean regularExpressionResult = !matcher.find();
+
+ boolean charsArrayResult = true;
+ try {
+ streamReader.checkPrintable(chars, 0, 1);
+ } catch (Exception e) {
+ String error = e.getMessage();
+ assertTrue(
+ error,
+ error.startsWith("unacceptable character")
+ || error.equals("special characters are not allowed"));
+ charsArrayResult = false;
+ }
+ assertEquals("Failed for #" + i, regularExpressionResult, charsArrayResult);
+ }
+ }
+
+ public void testForward() {
+ StreamReader reader = new StreamReader("test");
+ while (reader.peek() != '\u0000') {
+ reader.forward(1);
+ }
+ reader = new StreamReader("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() {
+ StreamReader reader = new StreamReader("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/recursive/AbstractHuman.java b/src/test/java/org/yaml/snakeyaml/recursive/AbstractHuman.java
new file mode 100644
index 0000000..a0ee333
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/recursive/AbstractHuman.java
@@ -0,0 +1,86 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.recursive;
+
+import java.util.Date;
+
+public abstract class AbstractHuman {
+ private String name;
+ private Date birthday;
+ private String birthPlace;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Date getBirthday() {
+ return birthday;
+ }
+
+ public void setBirthday(Date birthday) {
+ this.birthday = birthday;
+ }
+
+ public String getBirthPlace() {
+ return birthPlace;
+ }
+
+ public void setBirthPlace(String birthPlace) {
+ this.birthPlace = birthPlace;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((birthPlace == null) ? 0 : birthPlace.hashCode());
+ result = prime * result + ((birthday == null) ? 0 : birthday.hashCode());
+ result = prime * result + ((name == null) ? 0 : name.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ AbstractHuman other = (AbstractHuman) obj;
+ if (birthPlace == null) {
+ if (other.birthPlace != null)
+ return false;
+ } else if (!birthPlace.equals(other.birthPlace))
+ return false;
+ if (birthday == null) {
+ if (other.birthday != null)
+ return false;
+ } else if (!birthday.equals(other.birthday))
+ return false;
+ if (name == null) {
+ if (other.name != null)
+ return false;
+ } else if (!name.equals(other.name))
+ return false;
+ return true;
+ }
+
+}
diff --git a/src/test/java/org/yaml/snakeyaml/recursive/Human.java b/src/test/java/org/yaml/snakeyaml/recursive/Human.java
new file mode 100644
index 0000000..1ff91ae
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/recursive/Human.java
@@ -0,0 +1,73 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.recursive;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public class Human extends AbstractHuman {
+
+ private Human father;
+ private Human mother;
+ private Human partner;
+ private Human bankAccountOwner;
+ protected Set<Human> children;
+
+ public Human() {
+ children = new HashSet<Human>();
+ }
+
+ public Human getFather() {
+ return father;
+ }
+
+ public void setFather(Human father) {
+ this.father = father;
+ }
+
+ public Human getMother() {
+ return mother;
+ }
+
+ public void setMother(Human mother) {
+ this.mother = mother;
+ }
+
+ public Human getPartner() {
+ return partner;
+ }
+
+ public void setPartner(Human partner) {
+ this.partner = partner;
+ }
+
+ public Human getBankAccountOwner() {
+ return bankAccountOwner;
+ }
+
+ public void setBankAccountOwner(Human bankAccountOwner) {
+ this.bankAccountOwner = bankAccountOwner;
+ }
+
+ public Set<Human> getChildren() {
+ return children;
+ }
+
+ public void setChildren(Set<Human> children) {
+ this.children = children;
+ }
+
+}
diff --git a/src/test/java/org/yaml/snakeyaml/recursive/Human2.java b/src/test/java/org/yaml/snakeyaml/recursive/Human2.java
new file mode 100644
index 0000000..d056c72
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/recursive/Human2.java
@@ -0,0 +1,73 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.recursive;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class Human2 extends AbstractHuman {
+
+ private Human2 father;
+ private Human2 mother;
+ private Human2 partner;
+ private Human2 bankAccountOwner;
+ protected Map<Human2, String> children;
+
+ public Human2() {
+ children = new HashMap<Human2, String>();
+ }
+
+ public Human2 getFather() {
+ return father;
+ }
+
+ public void setFather(Human2 father) {
+ this.father = father;
+ }
+
+ public Human2 getMother() {
+ return mother;
+ }
+
+ public void setMother(Human2 mother) {
+ this.mother = mother;
+ }
+
+ public Human2 getPartner() {
+ return partner;
+ }
+
+ public void setPartner(Human2 partner) {
+ this.partner = partner;
+ }
+
+ public Human2 getBankAccountOwner() {
+ return bankAccountOwner;
+ }
+
+ public void setBankAccountOwner(Human2 bankAccountOwner) {
+ this.bankAccountOwner = bankAccountOwner;
+ }
+
+ public Map<Human2, String> getChildren() {
+ return children;
+ }
+
+ public void setChildren(Map<Human2, String> children) {
+ this.children = children;
+ }
+
+}
diff --git a/src/test/java/org/yaml/snakeyaml/recursive/Human3.java b/src/test/java/org/yaml/snakeyaml/recursive/Human3.java
new file mode 100644
index 0000000..41bda1f
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/recursive/Human3.java
@@ -0,0 +1,73 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.recursive;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Human3 extends AbstractHuman {
+
+ private Human3 father;
+ private Human3 mother;
+ private Human3 partner;
+ private Human3 bankAccountOwner;
+ protected List<Human3> children;
+
+ public Human3() {
+ children = new ArrayList<Human3>();
+ }
+
+ public Human3 getFather() {
+ return father;
+ }
+
+ public void setFather(Human3 father) {
+ this.father = father;
+ }
+
+ public Human3 getMother() {
+ return mother;
+ }
+
+ public void setMother(Human3 mother) {
+ this.mother = mother;
+ }
+
+ public Human3 getPartner() {
+ return partner;
+ }
+
+ public void setPartner(Human3 partner) {
+ this.partner = partner;
+ }
+
+ public Human3 getBankAccountOwner() {
+ return bankAccountOwner;
+ }
+
+ public void setBankAccountOwner(Human3 bankAccountOwner) {
+ this.bankAccountOwner = bankAccountOwner;
+ }
+
+ public List<Human3> getChildren() {
+ return children;
+ }
+
+ public void setChildren(List<Human3> children) {
+ this.children = children;
+ }
+
+}
diff --git a/src/test/java/org/yaml/snakeyaml/recursive/HumanTest.java b/src/test/java/org/yaml/snakeyaml/recursive/HumanTest.java
new file mode 100644
index 0000000..eab247e
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/recursive/HumanTest.java
@@ -0,0 +1,658 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.recursive;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.DumperOptions.FlowStyle;
+import org.yaml.snakeyaml.TypeDescription;
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.Constructor;
+
+public class HumanTest extends TestCase {
+
+ public void testNoChildren() {
+ Human father = new Human();
+ father.setName("Father");
+ father.setBirthday(new Date(1000000000));
+ father.setBirthPlace("Leningrad");
+ father.setBankAccountOwner(father);
+ Human mother = new Human();
+ mother.setName("Mother");
+ mother.setBirthday(new Date(100000000000L));
+ mother.setBirthPlace("Saint-Petersburg");
+ father.setPartner(mother);
+ mother.setPartner(father);
+ mother.setBankAccountOwner(father);
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(father);
+ String etalon = Util.getLocalResource("recursive/no-children-1.yaml");
+ assertEquals(etalon, output);
+ //
+ Human father2 = (Human) yaml.load(output);
+ assertNotNull(father2);
+ assertEquals("Father", father2.getName());
+ assertEquals("Mother", father2.getPartner().getName());
+ assertEquals("Father", father2.getBankAccountOwner().getName());
+ assertSame(father2, father2.getBankAccountOwner());
+ }
+
+ public void testNoChildrenPretty() {
+ Human father = new Human();
+ father.setName("Father");
+ father.setBirthday(new Date(1000000000));
+ father.setBirthPlace("Leningrad");
+ father.setBankAccountOwner(father);
+ Human mother = new Human();
+ mother.setName("Mother");
+ mother.setBirthday(new Date(100000000000L));
+ mother.setBirthPlace("Saint-Petersburg");
+ father.setPartner(mother);
+ mother.setPartner(father);
+ mother.setBankAccountOwner(father);
+ DumperOptions options = new DumperOptions();
+ options.setPrettyFlow(true);
+ options.setDefaultFlowStyle(FlowStyle.FLOW);
+ Yaml yaml = new Yaml(options);
+ String output = yaml.dump(father);
+ String etalon = Util.getLocalResource("recursive/no-children-1-pretty.yaml");
+ assertEquals(etalon, output);
+ //
+ Human father2 = (Human) yaml.load(output);
+ assertNotNull(father2);
+ assertEquals("Father", father2.getName());
+ assertEquals("Mother", father2.getPartner().getName());
+ assertEquals("Father", father2.getBankAccountOwner().getName());
+ assertSame(father2, father2.getBankAccountOwner());
+ }
+
+ public void testChildren() {
+ Human father = new Human();
+ father.setName("Father");
+ father.setBirthday(new Date(1000000000));
+ father.setBirthPlace("Leningrad");
+ father.setBankAccountOwner(father);
+ //
+ Human mother = new Human();
+ mother.setName("Mother");
+ mother.setBirthday(new Date(100000000000L));
+ mother.setBirthPlace("Saint-Petersburg");
+ father.setPartner(mother);
+ mother.setPartner(father);
+ mother.setBankAccountOwner(father);
+ //
+ Human son = new Human();
+ son.setName("Son");
+ son.setBirthday(new Date(310000000000L));
+ son.setBirthPlace("Munich");
+ son.setBankAccountOwner(father);
+ son.setFather(father);
+ son.setMother(mother);
+ //
+ Human daughter = new Human();
+ daughter.setName("Daughter");
+ daughter.setBirthday(new Date(420000000000L));
+ daughter.setBirthPlace("New York");
+ daughter.setBankAccountOwner(father);
+ daughter.setFather(father);
+ daughter.setMother(mother);
+ //
+ Set<Human> children = new LinkedHashSet<Human>(2);
+ children.add(son);
+ children.add(daughter);
+ father.setChildren(children);
+ mother.setChildren(children);
+ //
+ Yaml beanDumper = new Yaml();
+ String output = beanDumper.dumpAsMap(son);
+ // System.out.println(output);
+ String etalon = Util.getLocalResource("recursive/with-children.yaml");
+ assertEquals(etalon, output);
+ TypeDescription humanDescription = new TypeDescription(Human.class);
+ humanDescription.putMapPropertyType("children", Human.class, Object.class);
+ Yaml beanLoader = new Yaml(new Constructor(humanDescription));
+ //
+ Human son2 = beanLoader.loadAs(output, Human.class);
+ assertNotNull(son2);
+ assertEquals("Son", son.getName());
+
+ Human father2 = son2.getFather();
+ assertEquals("Father", father2.getName());
+ assertEquals("Mother", son2.getMother().getName());
+ assertSame(father2, father2.getBankAccountOwner());
+ assertSame(father2.getPartner(), son2.getMother());
+ assertSame(father2, son2.getMother().getPartner());
+
+ Set<Human> children2 = father2.getChildren();
+ assertEquals(2, children2.size());
+ assertSame(father2.getPartner().getChildren(), children2);
+
+ for (Object child : children2) {
+ // check if type descriptor was correct
+ assertSame(Human.class, child.getClass());
+ }
+
+ // check if hashCode is correct
+ validateSet(children2);
+ }
+
+ public void testChildrenPretty() {
+ Human father = new Human();
+ father.setName("Father");
+ father.setBirthday(new Date(1000000000));
+ father.setBirthPlace("Leningrad");
+ father.setBankAccountOwner(father);
+ //
+ Human mother = new Human();
+ mother.setName("Mother");
+ mother.setBirthday(new Date(100000000000L));
+ mother.setBirthPlace("Saint-Petersburg");
+ father.setPartner(mother);
+ mother.setPartner(father);
+ mother.setBankAccountOwner(father);
+ //
+ Human son = new Human();
+ son.setName("Son");
+ son.setBirthday(new Date(310000000000L));
+ son.setBirthPlace("Munich");
+ son.setBankAccountOwner(father);
+ son.setFather(father);
+ son.setMother(mother);
+ //
+ Human daughter = new Human();
+ daughter.setName("Daughter");
+ daughter.setBirthday(new Date(420000000000L));
+ daughter.setBirthPlace("New York");
+ daughter.setBankAccountOwner(father);
+ daughter.setFather(father);
+ daughter.setMother(mother);
+ //
+ Set<Human> children = new LinkedHashSet<Human>(2);
+ children.add(son);
+ children.add(daughter);
+ father.setChildren(children);
+ mother.setChildren(children);
+ //
+ DumperOptions options = new DumperOptions();
+ options.setDefaultFlowStyle(FlowStyle.FLOW);
+ options.setPrettyFlow(true);
+ Yaml beanDumper = new Yaml(options);
+ String output = beanDumper.dump(son);
+ // System.out.println(output);
+ String etalon = Util.getLocalResource("recursive/with-children-pretty.yaml");
+ assertEquals(etalon, output);
+ TypeDescription humanDescription = new TypeDescription(Human.class);
+ humanDescription.putMapPropertyType("children", Human.class, Object.class);
+ Yaml beanLoader = new Yaml(new Constructor(humanDescription));
+ //
+ Human son2 = beanLoader.loadAs(output, Human.class);
+ assertNotNull(son2);
+ assertEquals("Son", son.getName());
+
+ Human father2 = son2.getFather();
+ assertEquals("Father", father2.getName());
+ assertEquals("Mother", son2.getMother().getName());
+ assertSame(father2, father2.getBankAccountOwner());
+ assertSame(father2.getPartner(), son2.getMother());
+ assertSame(father2, son2.getMother().getPartner());
+
+ Set<Human> children2 = father2.getChildren();
+ assertEquals(2, children2.size());
+ assertSame(father2.getPartner().getChildren(), children2);
+
+ for (Object child : children2) {
+ // check if type descriptor was correct
+ assertSame(Human.class, child.getClass());
+ }
+
+ // check if hashCode is correct
+ validateSet(children2);
+ }
+
+ public void testChildren2() {
+ Human2 father = new Human2();
+ father.setName("Father");
+ father.setBirthday(new Date(1000000000));
+ father.setBirthPlace("Leningrad");
+ father.setBankAccountOwner(father);
+ //
+ Human2 mother = new Human2();
+ mother.setName("Mother");
+ mother.setBirthday(new Date(100000000000L));
+ mother.setBirthPlace("Saint-Petersburg");
+ father.setPartner(mother);
+ mother.setPartner(father);
+ mother.setBankAccountOwner(father);
+ //
+ Human2 son = new Human2();
+ son.setName("Son");
+ son.setBirthday(new Date(310000000000L));
+ son.setBirthPlace("Munich");
+ son.setBankAccountOwner(father);
+ son.setFather(father);
+ son.setMother(mother);
+ //
+ Human2 daughter = new Human2();
+ daughter.setName("Daughter");
+ daughter.setBirthday(new Date(420000000000L));
+ daughter.setBirthPlace("New York");
+ daughter.setBankAccountOwner(father);
+ daughter.setFather(father);
+ daughter.setMother(mother);
+ //
+ HashMap<Human2, String> children = new LinkedHashMap<Human2, String>(2);
+ children.put(son, "son");
+ children.put(daughter, "daughter");
+ father.setChildren(children);
+ mother.setChildren(children);
+ //
+
+ Constructor constructor = new Constructor(Human2.class);
+ TypeDescription humanDescription = new TypeDescription(Human2.class);
+ humanDescription.putMapPropertyType("children", Human2.class, String.class);
+ constructor.addTypeDescription(humanDescription);
+
+ Yaml yaml = new Yaml(constructor);
+ String output = yaml.dump(son);
+ // System.out.println(output);
+ String etalon = Util.getLocalResource("recursive/with-children-2.yaml");
+ assertEquals(etalon, output);
+ //
+ Human2 son2 = (Human2) yaml.load(output);
+ assertNotNull(son2);
+ assertEquals("Son", son.getName());
+
+ Human2 father2 = son2.getFather();
+ assertEquals("Father", father2.getName());
+ assertEquals("Mother", son2.getMother().getName());
+ assertSame(father2, father2.getBankAccountOwner());
+ assertSame(father2.getPartner(), son2.getMother());
+ assertSame(father2, son2.getMother().getPartner());
+
+ Map<Human2, String> children2 = father2.getChildren();
+ assertEquals(2, children2.size());
+ assertSame(father2.getPartner().getChildren(), children2);
+
+ validateMapKeys(children2);
+ }
+
+ public void testChildren3() {
+ Human3 father = new Human3();
+ father.setName("Father");
+ father.setBirthday(new Date(1000000000));
+ father.setBirthPlace("Leningrad");
+ father.setBankAccountOwner(father);
+ //
+ Human3 mother = new Human3();
+ mother.setName("Mother");
+ mother.setBirthday(new Date(100000000000L));
+ mother.setBirthPlace("Saint-Petersburg");
+ father.setPartner(mother);
+ mother.setPartner(father);
+ mother.setBankAccountOwner(father);
+ //
+ Human3 son = new Human3();
+ son.setName("Son");
+ son.setBirthday(new Date(310000000000L));
+ son.setBirthPlace("Munich");
+ son.setBankAccountOwner(father);
+ son.setFather(father);
+ son.setMother(mother);
+ //
+ Human3 daughter = new Human3();
+ daughter.setName("Daughter");
+ daughter.setBirthday(new Date(420000000000L));
+ daughter.setBirthPlace("New York");
+ daughter.setBankAccountOwner(father);
+ daughter.setFather(father);
+ daughter.setMother(mother);
+ //
+ ArrayList<Human3> children = new ArrayList<Human3>();
+ children.add(son);
+ children.add(daughter);
+ father.setChildren(children);
+ mother.setChildren(children);
+ //
+
+ Constructor constructor = new Constructor(Human3.class);
+ TypeDescription Human3Description = new TypeDescription(Human3.class);
+ Human3Description.putListPropertyType("children", Human3.class);
+ constructor.addTypeDescription(Human3Description);
+
+ Yaml yaml = new Yaml(constructor);
+ String output = yaml.dump(son);
+ // System.out.println(output);
+ String etalon = Util.getLocalResource("recursive/with-children-3.yaml");
+ assertEquals(etalon, output);
+ //
+ Human3 son2 = (Human3) yaml.load(output);
+ assertNotNull(son2);
+ assertEquals("Son", son.getName());
+
+ Human3 father2 = son2.getFather();
+ assertEquals("Father", father2.getName());
+ assertEquals("Mother", son2.getMother().getName());
+ assertSame(father2, father2.getBankAccountOwner());
+ assertSame(father2.getPartner(), son2.getMother());
+ assertSame(father2, son2.getMother().getPartner());
+
+ List<Human3> children2 = father2.getChildren();
+ assertEquals(2, children2.size());
+ assertSame(father2.getPartner().getChildren(), children2);
+
+ for (Object child : children2) {
+ // check if type descriptor was correct
+ assertSame(Human3.class, child.getClass());
+ }
+ }
+
+ /*
+ * Loads same structure as created in testChildren. But root object is set
+ * of children
+ */
+ @SuppressWarnings("unchecked")
+ public void testChildrenSetAsRoot() {
+ String etalon = Util.getLocalResource("recursive/with-children-as-set.yaml");
+
+ Constructor constructor = new Constructor();
+ TypeDescription humanDescription = new TypeDescription(Human.class);
+ humanDescription.putMapPropertyType("children", Human.class, Object.class);
+ constructor.addTypeDescription(humanDescription);
+
+ Yaml yaml = new Yaml(constructor);
+ Set<Human> children2 = (Set<Human>) yaml.load(etalon);
+ assertNotNull(children2);
+ assertEquals(2, children2.size());
+
+ Human firstChild = children2.iterator().next();
+
+ Human father2 = firstChild.getFather();
+ assertEquals("Father", father2.getName());
+ assertEquals("Mother", firstChild.getMother().getName());
+ assertSame(father2, father2.getBankAccountOwner());
+ assertSame(father2.getPartner(), firstChild.getMother());
+ assertSame(father2, firstChild.getMother().getPartner());
+
+ assertSame(father2.getPartner().getChildren(), children2);
+
+ for (Object child : children2) {
+ // check if type descriptor was correct
+ assertSame(Human.class, child.getClass());
+ }
+
+ validateSet(children2);
+ }
+
+ /*
+ * Loads same structure as created in testChildren. But root object is map
+ * of children
+ */
+ @SuppressWarnings("unchecked")
+ public void testChildrenMapAsRoot() {
+ String etalon = Util.getLocalResource("recursive/with-children-as-map.yaml");
+
+ Constructor constructor = new Constructor();
+ TypeDescription Human2Description = new TypeDescription(Human2.class);
+ Human2Description.putMapPropertyType("children", Human2.class, String.class);
+ constructor.addTypeDescription(Human2Description);
+
+ Yaml yaml = new Yaml(constructor);
+ Map<Human2, String> children2 = (Map<Human2, String>) yaml.load(etalon);
+ assertNotNull(children2);
+ assertEquals(2, children2.size());
+
+ Entry<Human2, String> firstEntry = children2.entrySet().iterator().next();
+ Human2 firstChild = firstEntry.getKey();
+
+ Human2 father2 = firstChild.getFather();
+ assertEquals("Father", father2.getName());
+ assertEquals("Mother", firstChild.getMother().getName());
+ assertSame(father2, father2.getBankAccountOwner());
+ assertSame(father2.getPartner(), firstChild.getMother());
+ assertSame(father2, firstChild.getMother().getPartner());
+
+ assertSame(father2.getPartner().getChildren(), children2);
+
+ validateMapKeys(children2);
+ }
+
+ /*
+ * Loads same structure as created in testChildren. But root object is list
+ * of children
+ */
+ @SuppressWarnings("unchecked")
+ public void testChildrenListRoot() {
+ Human3 father = new Human3();
+ father.setName("Father");
+ father.setBirthday(new Date(1000000000));
+ father.setBirthPlace("Leningrad");
+ father.setBankAccountOwner(father);
+ //
+ Human3 mother = new Human3();
+ mother.setName("Mother");
+ mother.setBirthday(new Date(100000000000L));
+ mother.setBirthPlace("Saint-Petersburg");
+ father.setPartner(mother);
+ mother.setPartner(father);
+ mother.setBankAccountOwner(father);
+ //
+ Human3 son = new Human3();
+ son.setName("Son");
+ son.setBirthday(new Date(310000000000L));
+ son.setBirthPlace("Munich");
+ son.setBankAccountOwner(father);
+ son.setFather(father);
+ son.setMother(mother);
+ //
+ Human3 daughter = new Human3();
+ daughter.setName("Daughter");
+ daughter.setBirthday(new Date(420000000000L));
+ daughter.setBirthPlace("New York");
+ daughter.setBankAccountOwner(father);
+ daughter.setFather(father);
+ daughter.setMother(mother);
+ //
+ ArrayList<Human3> children = new ArrayList<Human3>();
+ children.add(son);
+ children.add(daughter);
+ father.setChildren(children);
+ mother.setChildren(children);
+ //
+
+ Constructor constructor = new Constructor();
+ TypeDescription Human3Description = new TypeDescription(Human3.class);
+ Human3Description.putListPropertyType("children", Human3.class);
+ constructor.addTypeDescription(Human3Description);
+
+ Yaml yaml = new Yaml(constructor);
+ String output = yaml.dump(father.getChildren());
+ // System.out.println(output);
+ String etalon = Util.getLocalResource("recursive/with-children-as-list.yaml");
+ assertEquals(etalon, output);
+ //
+ List<Human3> children2 = (List<Human3>) yaml.load(output);
+ assertNotNull(children2);
+ Human3 son2 = children2.iterator().next();
+ assertEquals(2, children2.size());
+
+ Human3 father2 = son2.getFather();
+ assertEquals("Father", father2.getName());
+ assertEquals("Mother", son2.getMother().getName());
+ assertSame(father2, father2.getBankAccountOwner());
+ assertSame(father2.getPartner(), son2.getMother());
+ assertSame(father2, son2.getMother().getPartner());
+
+ assertSame(father2.getPartner().getChildren(), children2);
+
+ for (Object child : children2) {
+ // check if type descriptor was correct
+ assertSame(Human3.class, child.getClass());
+ }
+ }
+
+ public void testBeanRing() {
+ Human man1 = new Human();
+ man1.setName("Man 1");
+ Human man2 = new Human();
+ man2.setName("Man 2");
+ Human man3 = new Human();
+ man3.setName("Man 3");
+ man1.setBankAccountOwner(man2);
+ man2.setBankAccountOwner(man3);
+ man3.setBankAccountOwner(man1);
+ //
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(man1);
+ // System.out.println(output);
+ String etalon = Util.getLocalResource("recursive/beanring-3.yaml");
+ assertEquals(etalon, output);
+ //
+ Human loadedMan1 = (Human) yaml.load(output);
+ assertNotNull(loadedMan1);
+ assertEquals("Man 1", loadedMan1.getName());
+ Human loadedMan2 = loadedMan1.getBankAccountOwner();
+ Human loadedMan3 = loadedMan2.getBankAccountOwner();
+ assertSame(loadedMan1, loadedMan3.getBankAccountOwner());
+ }
+
+ public void qtestCollectionRing() {
+ // Set<Object> set = new HashSet<Object>();
+ // List<Object> list = new ArrayList<Object>();
+ // Map<Object, Object> map = new HashMap<Object, Object>();
+ // set.add(list);
+ // list.add(map);
+ // map.put("1", set);
+ // //
+ // try {
+ // Yaml yaml = new Yaml();
+ // String output = yaml.dump(set);
+ // // String etalon = Util.getLocalResource("recursive/???.yaml");
+ // // assertEquals(etalon, output);
+ // //
+ // // Set<Object> loadedSet = (Set<Object>) yaml.load(output);
+ // } catch (StackOverflowError e) {
+ // fail("Cannot dump recursive collections.");
+ // }
+ }
+
+ /**
+ * Checks if object was put into the set after full construction. So the
+ * hashCode was calculated correctly (if it depends on internal object's
+ * state).
+ *
+ * @param set
+ */
+ private void validateSet(Set<?> set) {
+ for (Object object : set) {
+ assertTrue(set.contains(object));
+ }
+ }
+
+ /**
+ * Checks if object was put into the map as key after full construction. So
+ * the hashCode was calculated correctly (if it depends on internal object's
+ * state).
+ *
+ * @param map
+ */
+ private void validateMapKeys(Map<?, ?> map) {
+ for (Map.Entry<?, ?> entry : map.entrySet()) {
+ assertTrue(map.containsKey(entry.getKey()));
+ }
+ }
+
+ public void testChildrenWithoutRootTag() {
+ Human father = new Human();
+ father.setName("Father");
+ father.setBirthday(new Date(1000000000));
+ father.setBirthPlace("Leningrad");
+ father.setBankAccountOwner(father);
+ //
+ Human mother = new Human();
+ mother.setName("Mother");
+ mother.setBirthday(new Date(100000000000L));
+ mother.setBirthPlace("Saint-Petersburg");
+ father.setPartner(mother);
+ mother.setPartner(father);
+ mother.setBankAccountOwner(father);
+ //
+ Human son = new Human();
+ son.setName("Son");
+ son.setBirthday(new Date(310000000000L));
+ son.setBirthPlace("Munich");
+ son.setBankAccountOwner(father);
+ son.setFather(father);
+ son.setMother(mother);
+ //
+ Human daughter = new Human();
+ daughter.setName("Daughter");
+ daughter.setBirthday(new Date(420000000000L));
+ daughter.setBirthPlace("New York");
+ daughter.setBankAccountOwner(father);
+ daughter.setFather(father);
+ daughter.setMother(mother);
+ //
+ Set<Human> children = new LinkedHashSet<Human>(2);
+ children.add(son);
+ children.add(daughter);
+ father.setChildren(children);
+ mother.setChildren(children);
+ //
+ Yaml beanDumper = new Yaml();
+ String output = beanDumper.dumpAsMap(son);
+ // System.out.println(output);
+ String etalon = Util.getLocalResource("recursive/with-children-no-root-tag.yaml");
+ assertEquals(etalon, output);
+ TypeDescription humanDescription = new TypeDescription(Human.class);
+ humanDescription.putMapPropertyType("children", Human.class, Object.class);
+ Yaml beanLoader = new Yaml(new Constructor(humanDescription));
+ //
+ Human son2 = beanLoader.loadAs(output, Human.class);
+ assertNotNull(son2);
+ assertEquals("Son", son.getName());
+
+ Human father2 = son2.getFather();
+ assertEquals("Father", father2.getName());
+ assertEquals("Mother", son2.getMother().getName());
+ assertSame(father2, father2.getBankAccountOwner());
+ assertSame(father2.getPartner(), son2.getMother());
+ assertSame(father2, son2.getMother().getPartner());
+
+ Set<Human> children2 = father2.getChildren();
+ assertEquals(2, children2.size());
+ assertSame(father2.getPartner().getChildren(), children2);
+
+ for (Object child : children2) {
+ // check if type descriptor was correct
+ assertSame(Human.class, child.getClass());
+ }
+
+ // check if hashCode is correct
+ validateSet(children2);
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/recursive/Human_WithArrayOfChildrenTest.java b/src/test/java/org/yaml/snakeyaml/recursive/Human_WithArrayOfChildrenTest.java
new file mode 100644
index 0000000..b0d013c
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/recursive/Human_WithArrayOfChildrenTest.java
@@ -0,0 +1,183 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.recursive;
+
+import java.util.Date;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.TypeDescription;
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.Constructor;
+
+public class Human_WithArrayOfChildrenTest extends TestCase {
+
+ public static class Human_WithArrayOfChildren extends AbstractHuman {
+
+ private Human_WithArrayOfChildren father;
+ private Human_WithArrayOfChildren mother;
+ private Human_WithArrayOfChildren partner;
+ private Human_WithArrayOfChildren bankAccountOwner;
+ protected Human_WithArrayOfChildren[] children;
+
+ public Human_WithArrayOfChildren() {
+ children = new Human_WithArrayOfChildren[0];
+ }
+
+ public Human_WithArrayOfChildren getFather() {
+ return father;
+ }
+
+ public void setFather(Human_WithArrayOfChildren father) {
+ this.father = father;
+ }
+
+ public Human_WithArrayOfChildren getMother() {
+ return mother;
+ }
+
+ public void setMother(Human_WithArrayOfChildren mother) {
+ this.mother = mother;
+ }
+
+ public Human_WithArrayOfChildren getPartner() {
+ return partner;
+ }
+
+ public void setPartner(Human_WithArrayOfChildren partner) {
+ this.partner = partner;
+ }
+
+ public Human_WithArrayOfChildren getBankAccountOwner() {
+ return bankAccountOwner;
+ }
+
+ public void setBankAccountOwner(Human_WithArrayOfChildren bankAccountOwner) {
+ this.bankAccountOwner = bankAccountOwner;
+ }
+
+ public Human_WithArrayOfChildren[] getChildren() {
+ return children;
+ }
+
+ public void setChildren(Human_WithArrayOfChildren[] children) {
+ this.children = children;
+ }
+
+ }
+
+ private Human_WithArrayOfChildren createSon() {
+ Human_WithArrayOfChildren father = new Human_WithArrayOfChildren();
+ father.setName("Father");
+ father.setBirthday(new Date(1000000000));
+ father.setBirthPlace("Leningrad");
+ father.setBankAccountOwner(father);
+ //
+ Human_WithArrayOfChildren mother = new Human_WithArrayOfChildren();
+ mother.setName("Mother");
+ mother.setBirthday(new Date(100000000000L));
+ mother.setBirthPlace("Saint-Petersburg");
+ father.setPartner(mother);
+ mother.setPartner(father);
+ mother.setBankAccountOwner(father);
+ //
+ Human_WithArrayOfChildren son = new Human_WithArrayOfChildren();
+ son.setName("Son");
+ son.setBirthday(new Date(310000000000L));
+ son.setBirthPlace("Munich");
+ son.setBankAccountOwner(father);
+ son.setFather(father);
+ son.setMother(mother);
+ //
+ Human_WithArrayOfChildren daughter = new Human_WithArrayOfChildren();
+ daughter.setName("Daughter");
+ daughter.setBirthday(new Date(420000000000L));
+ daughter.setBirthPlace("New York");
+ daughter.setBankAccountOwner(father);
+ daughter.setFather(father);
+ daughter.setMother(mother);
+ //
+ Human_WithArrayOfChildren[] children = new Human_WithArrayOfChildren[] { son, daughter };
+ father.setChildren(children);
+ mother.setChildren(children);
+ //
+ return son;
+ }
+
+ private void checkSon(Human_WithArrayOfChildren son) {
+ assertNotNull(son);
+ assertEquals("Son", son.getName());
+
+ Human_WithArrayOfChildren father2 = son.getFather();
+ assertEquals("Father", father2.getName());
+ assertEquals("Mother", son.getMother().getName());
+ assertSame(father2, father2.getBankAccountOwner());
+ assertSame(father2.getPartner(), son.getMother());
+ assertSame(father2, son.getMother().getPartner());
+
+ Human_WithArrayOfChildren[] fathersChildren = father2.getChildren();
+ assertEquals(2, fathersChildren.length);
+ Human_WithArrayOfChildren[] mothersChildren = father2.getPartner().getChildren();
+ assertEquals(2, mothersChildren.length);
+ assertSame(mothersChildren, fathersChildren);
+
+ for (Object child : fathersChildren) {
+ // check if type descriptor was correct
+ assertSame(Human_WithArrayOfChildren.class, child.getClass());
+ }
+ }
+
+ public void testChildrenArray() {
+ Constructor constructor = new Constructor(Human_WithArrayOfChildren.class);
+ TypeDescription HumanWithChildrenArrayDescription = new TypeDescription(
+ Human_WithArrayOfChildren.class);
+ HumanWithChildrenArrayDescription.putListPropertyType("children",
+ Human_WithArrayOfChildren.class);
+ constructor.addTypeDescription(HumanWithChildrenArrayDescription);
+ Human_WithArrayOfChildren son = createSon();
+ Yaml yaml = new Yaml(constructor);
+ String output = yaml.dump(son);
+ // System.out.println(output);
+ String etalon = Util.getLocalResource("recursive/with-childrenArray.yaml");
+ assertEquals(etalon, output);
+ //
+ Human_WithArrayOfChildren son2 = (Human_WithArrayOfChildren) yaml.load(output);
+ checkSon(son2);
+ }
+
+ public void testDumpChildrenArrayWithoutRootTag() {
+ Yaml yaml = new Yaml();
+ Human_WithArrayOfChildren son = createSon();
+ String output = yaml.dumpAsMap(son);
+ // System.out.println(output);
+ String etalon = Util.getLocalResource("recursive/with-childrenArray-no-root-tag.yaml");
+ assertEquals(etalon, output);
+ }
+
+ public void testParseChildrenArrayWithoutRootTag() {
+ Constructor constructor = new Constructor(Human_WithArrayOfChildren.class);
+ TypeDescription HumanWithChildrenArrayDescription = new TypeDescription(
+ Human_WithArrayOfChildren.class);
+ HumanWithChildrenArrayDescription.putListPropertyType("children",
+ Human_WithArrayOfChildren.class);
+ constructor.addTypeDescription(HumanWithChildrenArrayDescription);
+ Yaml yaml = new Yaml(constructor);
+ String doc = Util.getLocalResource("recursive/with-childrenArray-no-root-tag.yaml");
+ Human_WithArrayOfChildren son2 = (Human_WithArrayOfChildren) yaml.load(doc);
+ checkSon(son2);
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/recursive/generics/AbstractHumanGen.java b/src/test/java/org/yaml/snakeyaml/recursive/generics/AbstractHumanGen.java
new file mode 100644
index 0000000..8a6a01b
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/recursive/generics/AbstractHumanGen.java
@@ -0,0 +1,94 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.recursive.generics;
+
+import java.util.Date;
+
+public abstract class AbstractHumanGen<T, K extends AbstractHumanGen<T, ?>> {
+ private String name;
+ private Date birthday;
+ private String birthPlace;
+ private K father;
+ private K mother;
+ private K partner;
+ private K bankAccountOwner;
+ protected T children;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Date getBirthday() {
+ return birthday;
+ }
+
+ public void setBirthday(Date birthday) {
+ this.birthday = birthday;
+ }
+
+ public String getBirthPlace() {
+ return birthPlace;
+ }
+
+ public K getFather() {
+ return father;
+ }
+
+ public void setFather(K father) {
+ this.father = father;
+ }
+
+ public K getMother() {
+ return mother;
+ }
+
+ public void setMother(K mother) {
+ this.mother = mother;
+ }
+
+ public void setBirthPlace(String birthPlace) {
+ this.birthPlace = birthPlace;
+ }
+
+ public T getChildren() {
+ return children;
+ }
+
+ public void setChildren(T children) {
+ this.children = children;
+ }
+
+ public K getPartner() {
+ return partner;
+ }
+
+ public void setPartner(K partner) {
+ this.partner = partner;
+ }
+
+ public K getBankAccountOwner() {
+ return bankAccountOwner;
+ }
+
+ public void setBankAccountOwner(K bankAccountOwner) {
+ this.bankAccountOwner = bankAccountOwner;
+ }
+
+}
diff --git a/src/test/java/org/yaml/snakeyaml/recursive/generics/HumanGen.java b/src/test/java/org/yaml/snakeyaml/recursive/generics/HumanGen.java
new file mode 100644
index 0000000..bf14d47
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/recursive/generics/HumanGen.java
@@ -0,0 +1,25 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.recursive.generics;
+
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+public class HumanGen extends AbstractHumanGen<Set<HumanGen>, HumanGen> {
+ public HumanGen() {
+ children = new LinkedHashSet<HumanGen>();
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/recursive/generics/HumanGen2.java b/src/test/java/org/yaml/snakeyaml/recursive/generics/HumanGen2.java
new file mode 100644
index 0000000..0045680
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/recursive/generics/HumanGen2.java
@@ -0,0 +1,26 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.recursive.generics;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class HumanGen2 extends AbstractHumanGen<Map<HumanGen2, String>, HumanGen2> {
+
+ public HumanGen2() {
+ children = new HashMap<HumanGen2, String>();
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/recursive/generics/HumanGen3.java b/src/test/java/org/yaml/snakeyaml/recursive/generics/HumanGen3.java
new file mode 100644
index 0000000..b05d136
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/recursive/generics/HumanGen3.java
@@ -0,0 +1,26 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.recursive.generics;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class HumanGen3 extends AbstractHumanGen<List<HumanGen3>, HumanGen3> {
+
+ public HumanGen3() {
+ children = new ArrayList<HumanGen3>();
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/recursive/generics/HumanGenericsTest.java b/src/test/java/org/yaml/snakeyaml/recursive/generics/HumanGenericsTest.java
new file mode 100644
index 0000000..5bc1a0e
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/recursive/generics/HumanGenericsTest.java
@@ -0,0 +1,499 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.recursive.generics;
+
+import java.beans.IntrospectionException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.TypeDescription;
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.generics.GenericsBugDetector;
+import org.yaml.snakeyaml.nodes.Tag;
+import org.yaml.snakeyaml.representer.Representer;
+
+public class HumanGenericsTest extends TestCase {
+
+ public void testNoChildren() throws IOException, IntrospectionException {
+ if (!GenericsBugDetector.isProperIntrospection()) {
+ return;
+ }
+ HumanGen father = new HumanGen();
+ father.setName("Father");
+ father.setBirthday(new Date(1000000000));
+ father.setBirthPlace("Leningrad");
+ father.setBankAccountOwner(father);
+ HumanGen mother = new HumanGen();
+ mother.setName("Mother");
+ mother.setBirthday(new Date(100000000000L));
+ mother.setBirthPlace("Saint-Petersburg");
+ father.setPartner(mother);
+ mother.setPartner(father);
+ mother.setBankAccountOwner(father);
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(father);
+ String etalon = Util.getLocalResource("recursive/generics/no-children-1.yaml");
+ assertEquals(etalon, output);
+ //
+ HumanGen father2 = (HumanGen) yaml.load(output);
+ assertNotNull(father2);
+ assertEquals("Father", father2.getName());
+ assertEquals("Mother", father2.getPartner().getName());
+ assertEquals("Father", father2.getBankAccountOwner().getName());
+ assertSame(father2, father2.getBankAccountOwner());
+ }
+
+ /**
+ * the YAML document should contain no global tags
+ *
+ * @throws IntrospectionException
+ */
+ public void testNoChildren2() throws IOException, IntrospectionException {
+ if (!GenericsBugDetector.isProperIntrospection()) {
+ return;
+ }
+ HumanGen father = new HumanGen();
+ father.setName("Father");
+ father.setBirthday(new Date(1000000000));
+ father.setBirthPlace("Leningrad");
+ father.setBankAccountOwner(father);
+ HumanGen mother = new HumanGen();
+ mother.setName("Mother");
+ mother.setBirthday(new Date(100000000000L));
+ mother.setBirthPlace("Saint-Petersburg");
+ father.setPartner(mother);
+ mother.setPartner(father);
+ mother.setBankAccountOwner(father);
+ Yaml yaml = new Yaml();
+ String output = yaml.dumpAsMap(father);
+ String etalon = Util.getLocalResource("recursive/generics/no-children-2.yaml");
+ assertEquals(etalon, output);
+ //
+ Yaml loader = new Yaml();
+ HumanGen father2 = (HumanGen) loader.loadAs(etalon, HumanGen.class);
+ assertNotNull(father2);
+ assertEquals("Father", father2.getName());
+ assertEquals("Mother", father2.getPartner().getName());
+ assertEquals("Father", father2.getBankAccountOwner().getName());
+ assertSame(father2, father2.getBankAccountOwner());
+ }
+
+ public void testChildren() throws IOException, IntrospectionException {
+ if (!GenericsBugDetector.isProperIntrospection()) {
+ return;
+ }
+ HumanGen father = new HumanGen();
+ father.setName("Father");
+ father.setBirthday(new Date(1000000000));
+ father.setBirthPlace("Leningrad");
+ father.setBankAccountOwner(father);
+ //
+ HumanGen mother = new HumanGen();
+ mother.setName("Mother");
+ mother.setBirthday(new Date(100000000000L));
+ mother.setBirthPlace("Saint-Petersburg");
+ father.setPartner(mother);
+ mother.setPartner(father);
+ mother.setBankAccountOwner(father);
+ //
+ HumanGen son = new HumanGen();
+ son.setName("Son");
+ son.setBirthday(new Date(310000000000L));
+ son.setBirthPlace("Munich");
+ son.setBankAccountOwner(father);
+ son.setFather(father);
+ son.setMother(mother);
+ //
+ HumanGen daughter = new HumanGen();
+ daughter.setName("Daughter");
+ daughter.setBirthday(new Date(420000000000L));
+ daughter.setBirthPlace("New York");
+ daughter.setBankAccountOwner(father);
+ daughter.setFather(father);
+ daughter.setMother(mother);
+ //
+ Set<HumanGen> children = new LinkedHashSet<HumanGen>(2);
+ children.add(son);
+ children.add(daughter);
+ father.setChildren(children);
+ mother.setChildren(children);
+ //
+
+ Constructor constructor = new Constructor();
+ TypeDescription humanDescription = new TypeDescription(HumanGen.class);
+ humanDescription.putMapPropertyType("children", HumanGen.class, Object.class);
+ constructor.addTypeDescription(humanDescription);
+
+ Yaml yaml = new Yaml(constructor);
+ String output = yaml.dump(son);
+ // System.out.println(output);
+ String etalon = Util.getLocalResource("recursive/generics/with-children.yaml");
+ assertEquals(etalon, output);
+ //
+ HumanGen son2 = (HumanGen) yaml.load(output);
+ assertNotNull(son2);
+ assertEquals("Son", son.getName());
+
+ HumanGen father2 = son2.getFather();
+ assertEquals("Father", father2.getName());
+ assertEquals("Mother", son2.getMother().getName());
+ assertSame(father2, father2.getBankAccountOwner());
+ assertSame(father2.getPartner(), son2.getMother());
+ assertSame(father2, son2.getMother().getPartner());
+
+ Set<HumanGen> children2 = father2.getChildren();
+ assertEquals(2, children2.size());
+ assertSame(father2.getPartner().getChildren(), children2);
+
+ for (Object child : children2) {
+ assertSame(HumanGen.class, child.getClass()); // check if type
+ // descriptor was correct
+ }
+ }
+
+ public void testChildren2() throws IOException, IntrospectionException {
+ if (!GenericsBugDetector.isProperIntrospection()) {
+ return;
+ }
+ HumanGen2 father = new HumanGen2();
+ father.setName("Father");
+ father.setBirthday(new Date(1000000000));
+ father.setBirthPlace("Leningrad");
+ father.setBankAccountOwner(father);
+ //
+ HumanGen2 mother = new HumanGen2();
+ mother.setName("Mother");
+ mother.setBirthday(new Date(100000000000L));
+ mother.setBirthPlace("Saint-Petersburg");
+ father.setPartner(mother);
+ mother.setPartner(father);
+ mother.setBankAccountOwner(father);
+ //
+ HumanGen2 son = new HumanGen2();
+ son.setName("Son");
+ son.setBirthday(new Date(310000000000L));
+ son.setBirthPlace("Munich");
+ son.setBankAccountOwner(father);
+ son.setFather(father);
+ son.setMother(mother);
+ //
+ HumanGen2 daughter = new HumanGen2();
+ daughter.setName("Daughter");
+ daughter.setBirthday(new Date(420000000000L));
+ daughter.setBirthPlace("New York");
+ daughter.setBankAccountOwner(father);
+ daughter.setFather(father);
+ daughter.setMother(mother);
+ //
+ HashMap<HumanGen2, String> children = new LinkedHashMap<HumanGen2, String>(2);
+ children.put(son, "son");
+ children.put(daughter, "daughter");
+ father.setChildren(children);
+ mother.setChildren(children);
+ //
+ Representer representer = new Representer();
+ representer.addClassTag(HumanGen2.class, Tag.MAP);
+ Yaml yaml = new Yaml(representer);
+ String output = yaml.dump(son);
+ // System.out.println(output);
+ String etalon = Util.getLocalResource("recursive/generics/with-children-2.yaml");
+ assertEquals(etalon, output);
+ // load
+ TypeDescription humanDescription = new TypeDescription(HumanGen2.class);
+ humanDescription.putMapPropertyType("children", HumanGen2.class, String.class);
+ Yaml beanLoader = new Yaml(new Constructor(humanDescription));
+ //
+ HumanGen2 son2 = beanLoader.loadAs(output, HumanGen2.class);
+ assertNotNull(son2);
+ assertEquals("Son", son.getName());
+
+ HumanGen2 father2 = son2.getFather();
+ assertEquals("Father", father2.getName());
+ assertEquals("Mother", son2.getMother().getName());
+ assertSame(father2, father2.getBankAccountOwner());
+ assertSame(father2.getPartner(), son2.getMother());
+ assertSame(father2, son2.getMother().getPartner());
+
+ Map<HumanGen2, String> children2 = father2.getChildren();
+ assertEquals(2, children2.size());
+ assertSame(father2.getPartner().getChildren(), children2);
+
+ }
+
+ public void testChildren3() throws IOException, IntrospectionException {
+ if (!GenericsBugDetector.isProperIntrospection()) {
+ return;
+ }
+ HumanGen3 father = new HumanGen3();
+ father.setName("Father");
+ father.setBirthday(new Date(1000000000));
+ father.setBirthPlace("Leningrad");
+ father.setBankAccountOwner(father);
+ //
+ HumanGen3 mother = new HumanGen3();
+ mother.setName("Mother");
+ mother.setBirthday(new Date(100000000000L));
+ mother.setBirthPlace("Saint-Petersburg");
+ father.setPartner(mother);
+ mother.setPartner(father);
+ mother.setBankAccountOwner(father);
+ //
+ HumanGen3 son = new HumanGen3();
+ son.setName("Son");
+ son.setBirthday(new Date(310000000000L));
+ son.setBirthPlace("Munich");
+ son.setBankAccountOwner(father);
+ son.setFather(father);
+ son.setMother(mother);
+ //
+ HumanGen3 daughter = new HumanGen3();
+ daughter.setName("Daughter");
+ daughter.setBirthday(new Date(420000000000L));
+ daughter.setBirthPlace("New York");
+ daughter.setBankAccountOwner(father);
+ daughter.setFather(father);
+ daughter.setMother(mother);
+ //
+ ArrayList<HumanGen3> children = new ArrayList<HumanGen3>();
+ children.add(son);
+ children.add(daughter);
+ father.setChildren(children);
+ mother.setChildren(children);
+ //
+
+ Constructor constructor = new Constructor();
+ TypeDescription Human3Description = new TypeDescription(HumanGen3.class);
+ Human3Description.putListPropertyType("children", HumanGen3.class);
+ constructor.addTypeDescription(Human3Description);
+
+ Yaml yaml = new Yaml(constructor);
+ String output = yaml.dump(son);
+ // System.out.println(output);
+ String etalon = Util.getLocalResource("recursive/generics/with-children-3.yaml");
+ assertEquals(etalon, output);
+ //
+ HumanGen3 son2 = (HumanGen3) yaml.load(output);
+ assertNotNull(son2);
+ assertEquals("Son", son.getName());
+
+ HumanGen3 father2 = son2.getFather();
+ assertEquals("Father", father2.getName());
+ assertEquals("Mother", son2.getMother().getName());
+ assertSame(father2, father2.getBankAccountOwner());
+ assertSame(father2.getPartner(), son2.getMother());
+ assertSame(father2, son2.getMother().getPartner());
+
+ List<HumanGen3> children2 = father2.getChildren();
+ assertEquals(2, children2.size());
+ assertSame(father2.getPartner().getChildren(), children2);
+
+ for (Object child : children2) {
+ assertSame(HumanGen3.class, child.getClass()); // check if type
+ // descriptor was
+ // correct
+ }
+ }
+
+ /*
+ * Loads same structure as created in testChildren. But root object is set
+ * of children
+ */
+ @SuppressWarnings("unchecked")
+ public void testChildrenSetAsRoot() throws IOException, IntrospectionException {
+ if (!GenericsBugDetector.isProperIntrospection()) {
+ return;
+ }
+ String etalon = Util.getLocalResource("recursive/generics/with-children-as-set.yaml");
+
+ Constructor constructor = new Constructor();
+ TypeDescription humanDescription = new TypeDescription(HumanGen.class);
+ humanDescription.putMapPropertyType("children", HumanGen.class, Object.class);
+ constructor.addTypeDescription(humanDescription);
+
+ Yaml yaml = new Yaml(constructor);
+ Set<HumanGen> children2 = (Set<HumanGen>) yaml.load(etalon);
+ assertNotNull(children2);
+ assertEquals(2, children2.size());
+
+ HumanGen firstChild = children2.iterator().next();
+
+ HumanGen father2 = firstChild.getFather();
+ assertEquals("Father", father2.getName());
+ assertEquals("Mother", firstChild.getMother().getName());
+ assertSame(father2, father2.getBankAccountOwner());
+ assertSame(father2.getPartner(), firstChild.getMother());
+ assertSame(father2, firstChild.getMother().getPartner());
+
+ assertSame(father2.getPartner().getChildren(), children2);
+
+ for (Object child : children2) {
+ assertSame(HumanGen.class, child.getClass()); // check if type
+ // descriptor was correct
+ }
+ }
+
+ /*
+ * Loads same structure as created in testChildren. But root object is map
+ * of children
+ */
+ @SuppressWarnings("unchecked")
+ public void testChildrenMapAsRoot() throws IOException, IntrospectionException {
+ if (!GenericsBugDetector.isProperIntrospection()) {
+ return;
+ }
+ String etalon = Util.getLocalResource("recursive/generics/with-children-as-map.yaml");
+
+ Constructor constructor = new Constructor();
+ TypeDescription Human2Description = new TypeDescription(HumanGen2.class);
+ Human2Description.putMapPropertyType("children", HumanGen2.class, String.class);
+ constructor.addTypeDescription(Human2Description);
+
+ Yaml yaml = new Yaml(constructor);
+ Map<HumanGen2, String> children2 = (Map<HumanGen2, String>) yaml.load(etalon);
+ assertNotNull(children2);
+ assertEquals(2, children2.size());
+
+ Entry<HumanGen2, String> firstEntry = children2.entrySet().iterator().next();
+ HumanGen2 firstChild = firstEntry.getKey();
+
+ HumanGen2 father2 = firstChild.getFather();
+ assertEquals("Father", father2.getName());
+ assertEquals("Mother", firstChild.getMother().getName());
+ assertSame(father2, father2.getBankAccountOwner());
+ assertSame(father2.getPartner(), firstChild.getMother());
+ assertSame(father2, firstChild.getMother().getPartner());
+
+ assertSame(father2.getPartner().getChildren(), children2);
+ }
+
+ /*
+ * Loads same structure as created in testChildren. But root object is list
+ * of children
+ */
+ @SuppressWarnings("unchecked")
+ public void testChildrenListRoot() throws IOException, IntrospectionException {
+ if (!GenericsBugDetector.isProperIntrospection()) {
+ return;
+ }
+ HumanGen3 father = new HumanGen3();
+ father.setName("Father");
+ father.setBirthday(new Date(1000000000));
+ father.setBirthPlace("Leningrad");
+ father.setBankAccountOwner(father);
+ //
+ HumanGen3 mother = new HumanGen3();
+ mother.setName("Mother");
+ mother.setBirthday(new Date(100000000000L));
+ mother.setBirthPlace("Saint-Petersburg");
+ father.setPartner(mother);
+ mother.setPartner(father);
+ mother.setBankAccountOwner(father);
+ //
+ HumanGen3 son = new HumanGen3();
+ son.setName("Son");
+ son.setBirthday(new Date(310000000000L));
+ son.setBirthPlace("Munich");
+ son.setBankAccountOwner(father);
+ son.setFather(father);
+ son.setMother(mother);
+ //
+ HumanGen3 daughter = new HumanGen3();
+ daughter.setName("Daughter");
+ daughter.setBirthday(new Date(420000000000L));
+ daughter.setBirthPlace("New York");
+ daughter.setBankAccountOwner(father);
+ daughter.setFather(father);
+ daughter.setMother(mother);
+ //
+ ArrayList<HumanGen3> children = new ArrayList<HumanGen3>();
+ children.add(son);
+ children.add(daughter);
+ father.setChildren(children);
+ mother.setChildren(children);
+ //
+
+ Constructor constructor = new Constructor();
+ TypeDescription Human3Description = new TypeDescription(HumanGen3.class);
+ Human3Description.putListPropertyType("children", HumanGen3.class);
+ constructor.addTypeDescription(Human3Description);
+
+ Yaml yaml = new Yaml(constructor);
+ String output = yaml.dump(father.getChildren());
+ // System.out.println(output);
+ String etalon = Util.getLocalResource("recursive/generics/with-children-as-list.yaml");
+ assertEquals(etalon, output);
+ //
+ List<HumanGen3> children2 = (List<HumanGen3>) yaml.load(output);
+ assertNotNull(children2);
+ HumanGen3 son2 = children2.iterator().next();
+ assertEquals(2, children2.size());
+
+ HumanGen3 father2 = son2.getFather();
+ assertEquals("Father", father2.getName());
+ assertEquals("Mother", son2.getMother().getName());
+ assertSame(father2, father2.getBankAccountOwner());
+ assertSame(father2.getPartner(), son2.getMother());
+ assertSame(father2, son2.getMother().getPartner());
+
+ assertSame(father2.getPartner().getChildren(), children2);
+
+ for (Object child : children2) {
+ assertSame(HumanGen3.class, child.getClass()); // check if type
+ // descriptor was
+ // correct
+ }
+ }
+
+ public void testBeanRing() throws IOException, IntrospectionException {
+ if (!GenericsBugDetector.isProperIntrospection()) {
+ return;
+ }
+ HumanGen man1 = new HumanGen();
+ man1.setName("Man 1");
+ HumanGen man2 = new HumanGen();
+ man2.setName("Man 2");
+ HumanGen man3 = new HumanGen();
+ man3.setName("Man 3");
+ man1.setBankAccountOwner(man2);
+ man2.setBankAccountOwner(man3);
+ man3.setBankAccountOwner(man1);
+ //
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(man1);
+ // System.out.println(output);
+ String etalon = Util.getLocalResource("recursive/generics/beanring-3.yaml");
+ assertEquals(etalon, output);
+ //
+ HumanGen loadedMan1 = (HumanGen) yaml.load(output);
+ assertNotNull(loadedMan1);
+ assertEquals("Man 1", loadedMan1.getName());
+ HumanGen loadedMan2 = loadedMan1.getBankAccountOwner();
+ HumanGen loadedMan3 = loadedMan2.getBankAccountOwner();
+ assertSame(loadedMan1, loadedMan3.getBankAccountOwner());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/representer/DumpStackTraceTest.java b/src/test/java/org/yaml/snakeyaml/representer/DumpStackTraceTest.java
new file mode 100644
index 0000000..38a5256
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/representer/DumpStackTraceTest.java
@@ -0,0 +1,65 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.representer;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+
+public class DumpStackTraceTest extends TestCase {
+
+ public void testJavaStackTrace() {
+ Yaml yaml = new Yaml();
+ String input = Util.getLocalResource("representer/stacktrace1.txt");
+ String result = yaml.dump(input);
+ // System.out.println(result);
+ assertEquals(result, yaml.dump(yaml.load(result)));
+ }
+
+ public void testJavaStackTraceWithNoSpecialCharacters() {
+ DumperOptions options = new DumperOptions();
+ options.setWidth(50);
+ Yaml yaml = new Yaml(options);
+ String input = Util.getLocalResource("representer/stacktrace2.txt");
+ assertEquals(-1, input.indexOf(':'));
+ assertEquals(-1, input.indexOf('\t'));
+ String result = yaml.dump(input);
+ // System.out.println(result);
+ assertEquals(result, yaml.dump(yaml.load(result)));
+ }
+
+ public void testJavaStackTraceWithTabs() {
+ Yaml yaml = new Yaml();
+ String input = Util.getLocalResource("representer/stacktrace3.txt");
+ assertEquals(-1, input.indexOf(':'));
+ assertTrue("Tabs must be used.", input.indexOf('\t') > 0);
+ String result = yaml.dump(input);
+ // System.out.println(result);
+ assertEquals(result, yaml.dump(yaml.load(result)));
+ }
+
+ public void testJavaStackTraceWithoutTabs() {
+ Yaml yaml = new Yaml();
+ String input = Util.getLocalResource("representer/stacktrace1.txt");
+ String result = (String) yaml.dump(input);
+ // System.out.println(result);
+ String etalon = Util.getLocalResource("representer/stacktrace1.yaml");
+ // http://code.google.com/p/snakeyaml/issues/detail?id=66
+ assertEquals(etalon, result);
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/representer/FilterPropertyToDumpTest.java b/src/test/java/org/yaml/snakeyaml/representer/FilterPropertyToDumpTest.java
new file mode 100644
index 0000000..41c6bf2
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/representer/FilterPropertyToDumpTest.java
@@ -0,0 +1,107 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.representer;
+
+import java.beans.IntrospectionException;
+import java.util.Set;
+import java.util.TreeSet;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.introspector.Property;
+
+public class FilterPropertyToDumpTest extends TestCase {
+
+ public void testFilterPropertyInJavaBeanDumper() {
+ BeanToRemoveProperty bean = new BeanToRemoveProperty();
+ bean.setNumber(24);
+ bean.setId("ID124");
+ Yaml d = new Yaml();
+ String dump = d.dumpAsMap(bean);
+ // System.out.println(dump);
+ assertEquals("id: ID124\nnumber: 24\n", dump);
+ }
+
+ public void testFilterPropertyInYaml() {
+ BeanToRemoveProperty bean = new BeanToRemoveProperty();
+ bean.setNumber(25);
+ bean.setId("ID125");
+ Yaml yaml = new Yaml(new MyRepresenter());
+ String dump = yaml.dumpAsMap(bean);
+ // System.out.println(dump);
+ assertEquals("number: 25\n", dump);
+ }
+
+ public void testDoNotFilterPropertyIncludeReadOnly() {
+ BeanToRemoveProperty bean = new BeanToRemoveProperty();
+ bean.setNumber(26);
+ bean.setId("ID126");
+ DumperOptions options = new DumperOptions();
+ options.setAllowReadOnlyProperties(true);
+ Yaml yaml = new Yaml(options);
+ String dump = yaml.dump(bean);
+ // System.out.println(dump);
+ assertEquals(
+ "!!org.yaml.snakeyaml.representer.FilterPropertyToDumpTest$BeanToRemoveProperty {id: ID126,\n number: 26, something: true}\n",
+ dump);
+ }
+
+ public class BeanToRemoveProperty {
+ private int number;
+ private String id;
+
+ public boolean isSomething() {
+ return true;
+ }
+
+ public int getNumber() {
+ return number;
+ }
+
+ public void setNumber(int number) {
+ this.number = number;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getId() {
+ return id;
+ }
+ }
+
+ private class MyRepresenter extends Representer {
+ @Override
+ protected Set<Property> getProperties(Class<? extends Object> type)
+ throws IntrospectionException {
+ Set<Property> set = super.getProperties(type);
+ Set<Property> filtered = new TreeSet<Property>();
+ if (type.equals(BeanToRemoveProperty.class)) {
+ // filter properties
+ for (Property prop : set) {
+ String name = prop.getName();
+ if (!name.equals("id")) {
+ filtered.add(prop);
+ }
+ }
+ }
+ return filtered;
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/representer/RepresentFieldTest.java b/src/test/java/org/yaml/snakeyaml/representer/RepresentFieldTest.java
new file mode 100644
index 0000000..feff49e
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/representer/RepresentFieldTest.java
@@ -0,0 +1,70 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.representer;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+
+public class RepresentFieldTest extends TestCase {
+
+ public void testRepresent1() {
+ Yaml yaml = new Yaml();
+ WrongJavaBean bean = new WrongJavaBean();
+ bean.packageField = "Value";// the field is present
+ bean.publicField = "Michael Jackson";
+ WrongJavaBean.staticField = "Another value";
+ String output = yaml.dump(bean);
+ assertEquals(
+ "!!org.yaml.snakeyaml.representer.WrongJavaBean {publicField: Michael Jackson}\n",
+ output);
+ }
+
+ public void testWrongNotPublicField() {
+ Yaml yaml = new Yaml();
+ WrongJavaBean bean = new WrongJavaBean();
+ bean.packageField = "Value";// the field is present
+ try {
+ yaml.load("!!org.yaml.snakeyaml.representer.WrongJavaBean {packageField: Gnome}\n");
+ fail("Only public fields can be used.");
+ } catch (Exception e) {
+ // TODO improve the error message - the pointer should be at the
+ // property name, not value
+ assertTrue(e.getMessage().startsWith(
+ "Cannot create property=packageField for JavaBean=WrongJavaBean"));
+ assertEquals(
+ "Unable to find property 'packageField' on class: org.yaml.snakeyaml.representer.WrongJavaBean",
+ e.getCause().getMessage());
+ }
+ }
+
+ public void testStaticField() {
+ Yaml yaml = new Yaml();
+ WrongJavaBean.staticField = "Value";// the field is present
+ try {
+ yaml.load("!!org.yaml.snakeyaml.representer.WrongJavaBean {staticField: Gnome}\n");
+ fail("Static fields cannot be used.");
+ } catch (Exception e) {
+ // TODO improve the error message - the pointer should be at the
+ // property name, not value
+ assertTrue(e.getMessage().startsWith(
+ "Cannot create property=staticField for JavaBean=WrongJavaBean"));
+ assertEquals(
+ "Unable to find property 'staticField' on class: org.yaml.snakeyaml.representer.WrongJavaBean",
+ e.getCause().getMessage());
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/representer/RepresentIterableTest.java b/src/test/java/org/yaml/snakeyaml/representer/RepresentIterableTest.java
new file mode 100644
index 0000000..339e71d
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/representer/RepresentIterableTest.java
@@ -0,0 +1,73 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.representer;
+
+import java.util.Iterator;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+
+/**
+ * Test @see <a href="http://code.google.com/p/snakeyaml/issues/detail?id=69">issue 69</a>
+ */
+public class RepresentIterableTest extends TestCase {
+
+ public void testIterable() {
+ Yaml yaml = new Yaml();
+ try {
+ yaml.dump(new CounterFactory());
+ fail("Iterable should not be treated as sequence by default.");
+ } catch (Exception e) {
+ assertEquals(
+ "No JavaBean properties found in org.yaml.snakeyaml.representer.RepresentIterableTest$CounterFactory",
+ e.getMessage());
+ }
+ }
+
+ public void testIterator() {
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(new Counter(7));
+ assertEquals("[0, 1, 2, 3, 4, 5, 6]\n", output);
+ }
+
+ private class CounterFactory implements Iterable<Integer> {
+ public Iterator<Integer> iterator() {
+ return new Counter(10);
+ }
+ }
+
+ private class Counter implements Iterator<Integer> {
+ private int max = 0;
+ private int counter = 0;
+
+ public Counter(int max) {
+ this.max = max;
+ }
+
+ public boolean hasNext() {
+ return counter < max;
+ }
+
+ public Integer next() {
+ return counter++;
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ }
+}
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 0000000..a68beaf
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/representer/RepresentTest.java
@@ -0,0 +1,90 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.representer;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.AbstractConstruct;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.ScalarNode;
+import org.yaml.snakeyaml.nodes.Tag;
+
+public class RepresentTest extends TestCase {
+
+ public void testCustomRepresenter() {
+ Yaml yaml = new Yaml(new MyConstructor(), new MyRepresenter());
+ 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(new Tag("!!Dice"), value);
+ }
+ }
+ }
+
+ class MyConstructor extends Constructor {
+ public MyConstructor() {
+ this.yamlConstructors.put(new Tag(Tag.PREFIX + "Dice"), new ConstructDice());
+ }
+
+ private class ConstructDice extends AbstractConstruct {
+ public Object construct(Node node) {
+ String val = (String) constructScalar((ScalarNode) node);
+ return new CustomBean(val.substring(0, 1), new Integer(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 0000000..db31062
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/representer/RepresenterTest.java
@@ -0,0 +1,192 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.representer;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.nodes.Tag;
+
+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);
+ DumperOptions options = new DumperOptions();
+ options.setAllowReadOnlyProperties(true);
+ Yaml yaml = new Yaml(options);
+ 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", false);
+ DumperOptions options = new DumperOptions();
+ options.setAllowReadOnlyProperties(true);
+ Yaml yaml = new Yaml(options);
+ try {
+ String str = yaml.dump(bean);
+ fail("Exception must be reported: " + str);
+ } catch (Exception e) {
+ assertTrue(true);
+ }
+ // no exception
+ MyBean3 bean2 = new MyBean3("Gnome", true);
+ String str = yaml.dump(bean2);
+ // isValid is no JavaBean property (it must be a primitive then)
+ assertEquals(
+ "isValid property must not be dumped.",
+ "!!org.yaml.snakeyaml.representer.RepresenterTest$MyBean3 {boolProperty: true, name: Gnome}\n",
+ str);
+ }
+
+ public static class MyBean3 {
+ private String name;
+ private Boolean valid;
+ private boolean boolProperty;
+
+ public MyBean3(String name, Boolean valid) {
+ this.name = name;
+ this.valid = valid;
+ boolProperty = true;
+ }
+
+ public String getName() {
+ if (valid) {
+ return name;
+ } else {
+ throw new UnsupportedOperationException("Test.");
+ }
+ }
+
+ public Boolean isValid() {
+ return valid;
+ }
+
+ public boolean isBoolProperty() {
+ return boolProperty;
+ }
+
+ @Override
+ public String toString() {
+ return "MyBean3<" + name + ", " + isValid() + ">";
+ }
+ }
+
+ public void testRepresenterAddNull() {
+ Representer representer = new Representer();
+ try {
+ representer.addClassTag(EmptyBean.class, (Tag) null);
+ fail("Tag must be provided.");
+ } catch (Exception e) {
+ assertEquals("Tag must be provided.", e.getMessage());
+ }
+ }
+
+ public void testRepresenterEmptyBean() {
+ EmptyBean bean = new EmptyBean();
+ Yaml yaml = new Yaml();
+ try {
+ yaml.dump(bean);
+ fail("EmptyBean has empty representation.");
+ } catch (Exception e) {
+ assertEquals(
+ "No JavaBean properties found in org.yaml.snakeyaml.representer.RepresenterTest$EmptyBean",
+ e.getMessage());
+ }
+ }
+
+ public static class EmptyBean {
+ private int number;
+
+ public void process() {
+ number += 1;
+ }
+
+ public int obtain() {
+ return number;
+ }
+ }
+}
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 0000000..719cf54
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/representer/SafeRepresenterTest.java
@@ -0,0 +1,137 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.representer;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+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;
+import org.yaml.snakeyaml.reader.StreamReader;
+
+public class SafeRepresenterTest extends TestCase {
+
+ public void testBinaryPattern() {
+ Pattern pattern = StreamReader.NON_PRINTABLE;
+ assertFalse(pattern.matcher("\tAndrey\r\n").find());
+ assertTrue(pattern.matcher("\u0005Andrey").find());
+ }
+
+ public void testFloat() {
+ assertEquals("1.0E12", String.valueOf(new Double("1e12")));
+ }
+
+ public void testNumber() {
+ List<Number> list = new ArrayList<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 ArrayList<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.FlowStyle.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 ArrayList<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.setDefaultScalarStyle(DumperOptions.ScalarStyle.DOUBLE_QUOTED);
+ options.setDefaultFlowStyle(DumperOptions.FlowStyle.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 ArrayList<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.setDefaultScalarStyle(DumperOptions.ScalarStyle.SINGLE_QUOTED);
+ options.setDefaultFlowStyle(DumperOptions.FlowStyle.FLOW);
+ Yaml yaml = new Yaml(options);
+ String output = yaml.dump(map);
+ assertEquals("{'age': !!int '5', 'name': 'Ubuntu', 'list': [!!int '1', !!int '1']}\n",
+ output);
+ }
+
+ public void testStyle2Pretty() {
+ List<Integer> list = new ArrayList<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.setDefaultScalarStyle(DumperOptions.ScalarStyle.SINGLE_QUOTED);
+ options.setDefaultFlowStyle(DumperOptions.FlowStyle.FLOW);
+ options.setPrettyFlow(true);
+ Yaml yaml = new Yaml(options);
+ String output = yaml.dump(map);
+ assertEquals(
+ "{\n 'age': !!int '5',\n 'name': 'Ubuntu',\n 'list': [\n !!int '1',\n !!int '1']\n \n}\n",
+ output);
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/representer/WrongJavaBean.java b/src/test/java/org/yaml/snakeyaml/representer/WrongJavaBean.java
new file mode 100644
index 0000000..729fc06
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/representer/WrongJavaBean.java
@@ -0,0 +1,37 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.representer;
+
+public class WrongJavaBean {
+ String packageField;
+ static String staticField;
+ public transient String dynamo;
+ public String publicField;
+ private int privateValue;
+
+ public WrongJavaBean() {
+ method();
+ }
+
+ private void method() {
+ privateValue++;
+ }
+
+ @Override
+ public String toString() {
+ return "WrongJavaBean";
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/resolver/ImplicitResolverTest.java b/src/test/java/org/yaml/snakeyaml/resolver/ImplicitResolverTest.java
new file mode 100644
index 0000000..10ff70e
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/resolver/ImplicitResolverTest.java
@@ -0,0 +1,95 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.resolver;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.TypeDescription;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.AbstractConstruct;
+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.nodes.Tag;
+
+/**
+ * Custom implicit resolver does not apply inside JavaBean declaration <a href=
+ * "http://groups.google.com/group/snakeyaml-core/browse_frm/thread/c75c35a3d9cfcaba"
+ * >mailing list</a> for more information
+ */
+public class ImplicitResolverTest extends TestCase {
+ private static final Tag CFG = new Tag("!cfg");
+
+ public static class ConfigurationConstructor extends Constructor {
+ protected Map<String, String> config = null;
+
+ public ConfigurationConstructor(Map<String, String> config) {
+ this.config = config;
+ this.yamlConstructors.put(CFG, new ConfigObjectConstruct());
+ }
+
+ private class ConfigObjectConstruct extends AbstractConstruct {
+ public Object construct(Node node) {
+ String val = (String) constructScalar((ScalarNode) node);
+ val = val.substring(2, val.length() - 1);
+ return config.get(val);
+ }
+ }
+
+ protected Construct getConstructor(Node node) {
+ if (CFG.equals(node.getTag())) {
+ node.setUseClassConstructor(false);
+ }
+ return super.getConstructor(node);
+ }
+ }
+
+ public static class TestBean {
+ String myval;
+
+ public String getMyval() {
+ return myval;
+ }
+
+ public void setMyval(String myval) {
+ this.myval = myval;
+ }
+
+ public String toString() {
+ return "MyVal: " + myval;
+ }
+ }
+
+ public void testMain() {
+ Map<String, String> config = new HashMap<String, String>();
+ config.put("user.home", "HOME");
+ Constructor constructor = new ConfigurationConstructor(config);
+ constructor.addTypeDescription(new TypeDescription(TestBean.class, "!testbean"));
+ Yaml yaml = new Yaml(constructor);
+ yaml.addImplicitResolver(CFG, Pattern.compile("\\$\\([a-zA-Z\\d\\u002E\\u005F]+\\)"), "$");
+ TestBean bean = (TestBean) yaml.load("!testbean {myval: !cfg $(user.home)}");
+ // System.out.println(bean.toString());
+ assertEquals("Explicit tag must be respected", "HOME", bean.getMyval());
+ bean = (TestBean) yaml.load("!testbean {myval: $(user.home)}");
+ // System.out.println(bean.toString());
+ assertEquals("Implicit tag must be respected", "HOME", bean.getMyval());
+ }
+}
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 0000000..c9a252d
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/resolver/ResolverTest.java
@@ -0,0 +1,150 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.resolver;
+
+import java.awt.Point;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+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;
+import org.yaml.snakeyaml.constructor.AbstractConstruct;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.ScalarNode;
+import org.yaml.snakeyaml.nodes.Tag;
+import org.yaml.snakeyaml.representer.Represent;
+import org.yaml.snakeyaml.representer.Representer;
+
+public class ResolverTest extends TestCase {
+
+ @SuppressWarnings("unchecked")
+ public void testAddImplicitResolver() {
+ Yaml yaml = new Yaml(new MyConstructor(), new MyRepresenter());
+ Pattern regexp = Pattern.compile("\\d\\d-\\d\\d-\\d\\d\\d");
+ yaml.addImplicitResolver(new Tag(Tag.PREFIX + "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 ArrayList<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() {
+ Yaml yaml = new Yaml(new PointRepresenter());
+ Pattern regexp = Pattern.compile("\\d\\d-\\d\\d-\\d\\d\\d");
+ yaml.addImplicitResolver(new Tag(Tag.PREFIX + "Phone"), regexp, "\0");
+ Pattern regexp2 = Pattern.compile("x\\d_y\\d");
+ // try any scalar, and not only those which start with 'x'
+ yaml.addImplicitResolver(new Tag(Tag.PREFIX + "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(new Tag(Tag.PREFIX + "Phone"), value);
+ }
+ }
+ }
+
+ class MyConstructor extends Constructor {
+ public MyConstructor() {
+ this.yamlConstructors.put(new Tag(Tag.PREFIX + "Phone"), new ConstructPhone());
+ }
+
+ private class ConstructPhone extends AbstractConstruct {
+ 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(new Tag(Tag.PREFIX + "Point"), value);
+ }
+ }
+
+ private class RepresentPhone implements Represent {
+ public Node representData(Object data) {
+ Phone phone = (Phone) data;
+ String value = phone.getNumber();
+ return representScalar(new Tag(Tag.PREFIX + "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 0000000..4cac651
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/resolver/ResolverTupleTest.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.resolver;
+
+import java.util.regex.Pattern;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.nodes.Tag;
+
+public class ResolverTupleTest extends TestCase {
+
+ public void testToString() {
+ ResolverTuple tuple = new ResolverTuple(new Tag("dice"), Pattern.compile("\\d+"));
+ assertEquals("Tuple tag=dice regexp=\\d+", tuple.toString());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/ruby/RubyTest.java b/src/test/java/org/yaml/snakeyaml/ruby/RubyTest.java
new file mode 100644
index 0000000..7eaae71
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/ruby/RubyTest.java
@@ -0,0 +1,113 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.ruby;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.TypeDescription;
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.nodes.Tag;
+import org.yaml.snakeyaml.representer.Representer;
+
+public class RubyTest extends TestCase {
+
+ public void testParse() {
+ TestObject result = parseObject(Util.getLocalResource("ruby/ruby1.yaml"));
+ assertNotNull(result);
+ assertEquals(0, result.getSub1().getAtt2());
+ assertEquals("MyString", result.getSub2().getAtt1());
+ assertEquals(1, result.getSub2().getAtt2().size());
+ assertEquals(12345, result.getSub2().getAtt3());
+ }
+
+ public void testEmitNoTags() {
+ TestObject result = parseObject(Util.getLocalResource("ruby/ruby1.yaml"));
+ DumperOptions options = new DumperOptions();
+ options.setExplicitStart(true);
+ Yaml yaml2 = new Yaml(options);
+ String output = yaml2.dumpAsMap(result);
+ assertFalse("No tags expected.", output.contains("Sub1"));
+ // System.out.println(output);
+ // parse back. Without tags it shall still work
+ Yaml beanLoader = new Yaml();
+ TestObject result2 = beanLoader.loadAs(output, TestObject.class);
+ assertEquals(0, result2.getSub1().getAtt2());
+ assertEquals("MyString", result2.getSub2().getAtt1());
+ assertEquals(1, result2.getSub2().getAtt2().size());
+ assertEquals(12345, result2.getSub2().getAtt3());
+ }
+
+ public void testEmitWithTags() {
+ TestObject result = parseObject(Util.getLocalResource("ruby/ruby1.yaml"));
+ DumperOptions options = new DumperOptions();
+ options.setExplicitStart(true);
+ Representer repr = new Representer();
+ repr.addClassTag(TestObject.class, new Tag("!ruby/object:Test::Module::Object"));
+ repr.addClassTag(Sub1.class, new Tag("!ruby/object:Test::Module::Sub1"));
+ repr.addClassTag(Sub2.class, new Tag("!ruby/object:Test::Module::Sub2"));
+ Yaml yaml2 = new Yaml(repr, options);
+ String output = yaml2.dump(result);
+ // System.out.println(output);
+ assertTrue("Tags must be present.",
+ output.startsWith("--- !ruby/object:Test::Module::Object"));
+ assertTrue("Tags must be present: " + output,
+ output.contains("!ruby/object:Test::Module::Sub1"));
+ assertTrue("Tags must be present.", output.contains("!ruby/object:Test::Module::Sub2"));
+ // parse back.
+ TestObject result2 = parseObject(output);
+ assertEquals(0, result2.getSub1().getAtt2());
+ assertEquals("MyString", result2.getSub2().getAtt1());
+ assertEquals(1, result2.getSub2().getAtt2().size());
+ assertEquals(12345, result2.getSub2().getAtt3());
+ }
+
+ public void testEmitWithTags2WithoutTagForParentJavabean() {
+ TestObject result = parseObject(Util.getLocalResource("ruby/ruby1.yaml"));
+ DumperOptions options = new DumperOptions();
+ options.setExplicitStart(true);
+ Representer repr = new Representer();
+ repr.addClassTag(Sub1.class, new Tag("!ruby/object:Test::Module::Sub1"));
+ repr.addClassTag(Sub2.class, new Tag("!ruby/object:Test::Module::Sub2"));
+ Yaml yaml2 = new Yaml(repr, options);
+ String output = yaml2.dump(result);
+ // System.out.println(output);
+ assertTrue("Tags must be present.",
+ output.startsWith("--- !!org.yaml.snakeyaml.ruby.TestObject"));
+ assertTrue("Tags must be present: " + output,
+ output.contains("!ruby/object:Test::Module::Sub1"));
+ assertTrue("Tags must be present.", output.contains("!ruby/object:Test::Module::Sub2"));
+ // parse back.
+ TestObject result2 = parseObject(output);
+ assertEquals(0, result2.getSub1().getAtt2());
+ assertEquals("MyString", result2.getSub2().getAtt1());
+ assertEquals(1, result2.getSub2().getAtt2().size());
+ assertEquals(12345, result2.getSub2().getAtt3());
+ }
+
+ private TestObject parseObject(String input) {
+ Constructor con = new Constructor(TestObject.class);
+ con.addTypeDescription(new TypeDescription(TestObject.class,
+ "!ruby/object:Test::Module::Object"));
+ con.addTypeDescription(new TypeDescription(Sub1.class, "!ruby/object:Test::Module::Sub1"));
+ con.addTypeDescription(new TypeDescription(Sub2.class, "!ruby/object:Test::Module::Sub2"));
+
+ Yaml yaml = new Yaml(con);
+ return (TestObject) yaml.load(input);
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/ruby/Sub1.java b/src/test/java/org/yaml/snakeyaml/ruby/Sub1.java
new file mode 100644
index 0000000..25618f4
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/ruby/Sub1.java
@@ -0,0 +1,48 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.ruby;
+
+import java.util.List;
+
+public class Sub1 {
+ private List<Integer> att1;
+ private int att2;
+ private List<Integer> att3;
+
+ public List<Integer> getAtt1() {
+ return att1;
+ }
+
+ public void setAtt1(List<Integer> att1) {
+ this.att1 = att1;
+ }
+
+ public int getAtt2() {
+ return att2;
+ }
+
+ public void setAtt2(int att2) {
+ this.att2 = att2;
+ }
+
+ public List<Integer> getAtt3() {
+ return att3;
+ }
+
+ public void setAtt3(List<Integer> att3) {
+ this.att3 = att3;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/ruby/Sub2.java b/src/test/java/org/yaml/snakeyaml/ruby/Sub2.java
new file mode 100644
index 0000000..d8548f6
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/ruby/Sub2.java
@@ -0,0 +1,49 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.ruby;
+
+import java.util.List;
+
+public class Sub2 {
+ private String att1;
+ private List<String> att2;
+ private int att3;
+
+ public String getAtt1() {
+ return att1;
+ }
+
+ public void setAtt1(String att1) {
+ this.att1 = att1;
+ }
+
+ public List<String> getAtt2() {
+ return att2;
+ }
+
+ public void setAtt2(List<String> att2) {
+ this.att2 = att2;
+ }
+
+ public int getAtt3() {
+ return att3;
+ }
+
+ public void setAtt3(int att3) {
+ this.att3 = att3;
+ }
+
+}
diff --git a/src/test/java/org/yaml/snakeyaml/ruby/TestObject.java b/src/test/java/org/yaml/snakeyaml/ruby/TestObject.java
new file mode 100644
index 0000000..2885d09
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/ruby/TestObject.java
@@ -0,0 +1,37 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.ruby;
+
+public class TestObject {
+ private Sub1 sub1;
+ private Sub2 sub2;
+
+ public Sub1 getSub1() {
+ return sub1;
+ }
+
+ public void setSub1(Sub1 sub1) {
+ this.sub1 = sub1;
+ }
+
+ public Sub2 getSub2() {
+ return sub2;
+ }
+
+ public void setSub2(Sub2 sub2) {
+ this.sub2 = sub2;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/scanner/ConstantTest.java b/src/test/java/org/yaml/snakeyaml/scanner/ConstantTest.java
new file mode 100644
index 0000000..8a39857
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/scanner/ConstantTest.java
@@ -0,0 +1,36 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.scanner;
+
+import junit.framework.TestCase;
+
+public class ConstantTest extends TestCase {
+
+ public void testHasChar() {
+ assertTrue(Constant.LINEBR.has('\n'));
+ assertTrue(Constant.LINEBR.has('\u0085'));
+ assertFalse(Constant.LINEBR.has(' '));
+ }
+
+ public void testHasStringChar() {
+ assertTrue(Constant.LINEBR.has(' ', " "));
+ }
+
+ public void testHas0() {
+ assertTrue(Constant.LINEBR.has((char) 0, "\0"));
+ }
+
+}
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 0000000..4e19412
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/scanner/ScannerImplTest.java
@@ -0,0 +1,70 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.scanner;
+
+import java.util.LinkedList;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.error.Mark;
+import org.yaml.snakeyaml.reader.StreamReader;
+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 {
+
+ public void testGetToken() {
+ String data = "string: abcd";
+ StreamReader reader = new StreamReader(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 (!etalonTokens.isEmpty() && scanner.checkToken(etalonTokens.get(0).getTokenId())) {
+ assertEquals(etalonTokens.removeFirst(), scanner.getToken());
+ }
+ assertFalse("Must contain no more tokens: " + scanner.getToken(),
+ scanner.checkToken(new Token.ID[0]));
+ }
+
+ public void testWrongTab() {
+ Yaml yaml = new Yaml();
+ try {
+ yaml.load("\t data: 1");
+ fail("TAB cannot start a token.");
+ } catch (Exception e) {
+ assertEquals(
+ "while scanning for the next token\n"
+ + "found character '\\t(TAB)' that cannot start any token. (Do not use \\t(TAB) for indentation)\n"
+ + " in 'string', line 1, column 1:\n" + " \t data: 1\n" + " ^\n",
+ e.getMessage());
+ }
+ }
+}
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 0000000..8c577f3
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/scanner/SimpleKeyTest.java
@@ -0,0 +1,26 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+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/AnchorGeneratorTest.java b/src/test/java/org/yaml/snakeyaml/serializer/AnchorGeneratorTest.java
new file mode 100644
index 0000000..82c04fb
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/serializer/AnchorGeneratorTest.java
@@ -0,0 +1,68 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.serializer;
+
+import junit.framework.TestCase;
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.Tag;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class AnchorGeneratorTest extends TestCase {
+
+ public void testNext() {
+ AnchorGenerator generator = new NumberAnchorGenerator(0);
+ assertEquals("id001", generator.nextAnchor(null));
+ assertEquals("id002", generator.nextAnchor(null));
+ }
+
+ public void testCustomGenerator() {
+ List<Object> list = new ArrayList<Object>();
+ list.add("data123");
+ list.add(list);
+ Yaml yaml1 = new Yaml();
+ String output = yaml1.dump(list);
+ assertEquals("&id001\n" +
+ "- data123\n" +
+ "- *id001\n", output);
+
+
+ DumperOptions options = new DumperOptions();
+ Yaml yaml2 = new Yaml(options);
+ options.setAnchorGenerator(new Gener(3));
+ String output2 = yaml2.dump(list);
+ assertEquals("&list-id004\n" +
+ "- data123\n" +
+ "- *list-id004\n", output2);
+ }
+
+ class Gener extends NumberAnchorGenerator {
+
+ public Gener(int lastAnchorId) {
+ super(lastAnchorId);
+ }
+
+ public String nextAnchor(Node node) {
+ if (node.getTag() == Tag.SEQ)
+ return "list-" + super.nextAnchor(node);
+ else
+ return super.nextAnchor(node);
+ }
+ }
+}
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 0000000..69eaca4
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/serializer/SerializerTest.java
@@ -0,0 +1,102 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+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.nodes.Tag;
+import org.yaml.snakeyaml.resolver.Resolver;
+
+public class SerializerTest extends TestCase {
+ private Serializer serializer;
+
+ @Override
+ protected void setUp() {
+ DumperOptions config = new DumperOptions();
+ StringWriter writer = new StringWriter();
+ serializer = new Serializer(new Emitter(writer, config), new Resolver(), config, null);
+ }
+
+ 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(new Tag("!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(new Tag("!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/stress/ParallelTest.java b/src/test/java/org/yaml/snakeyaml/stress/ParallelTest.java
new file mode 100644
index 0000000..3bae53f
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/stress/ParallelTest.java
@@ -0,0 +1,71 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.stress;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Invoice;
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+
+/**
+ * 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() {
+ 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);
+ Yaml loader = new Yaml();
+ long time1 = System.nanoTime();
+ int cycles = 200;
+ for (int i = 0; i < cycles; i++) {
+ Invoice invoice = loader.loadAs(doc, Invoice.class);
+ assertNotNull(invoice);
+ }
+ long time2 = System.nanoTime();
+ float duration = ((time2 - time1) / 1000000) / (float) cycles;
+ System.out.println("Duration of " + id + " was " + duration + " ms/load.");
+ progress++;
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/stress/StressEmitterTest.java b/src/test/java/org/yaml/snakeyaml/stress/StressEmitterTest.java
new file mode 100644
index 0000000..5185e02
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/stress/StressEmitterTest.java
@@ -0,0 +1,80 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.stress;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import org.yaml.snakeyaml.Invoice;
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+
+public class StressEmitterTest extends TestCase {
+
+ public static void main(String args[]) {
+ junit.textui.TestRunner.run(suite());
+ }
+
+ public static Test suite() {
+ return new TestSuite(StressEmitterTest.class);
+ }
+
+ public void testPerformance() {
+ Yaml loader = new Yaml();
+ Invoice invoice = loader.loadAs(Util.getLocalResource("specification/example2_27.yaml"),
+ Invoice.class);
+ Yaml dumper = new Yaml();
+ long time1 = System.nanoTime();
+ dumper.dumpAsMap(invoice);
+ long time2 = System.nanoTime();
+ float duration = (time2 - time1) / 1000000;
+ System.out.println("\nSingle dump was " + duration + " ms.");
+
+ int[] range = new int[] { 1000, 2000 /* , 8000 */};
+ System.out.println("\nOne instance.");
+ for (int number : range) {
+ time1 = System.nanoTime();
+ for (int i = 0; i < number; i++) {
+ dumper.dump(invoice);
+ }
+ time2 = System.nanoTime();
+ duration = ((time2 - time1) / 1000000) / (float) number;
+ System.out.println("Duration for r=" + number + " was " + duration + " ms/dump.");
+ // cobertura may make it very slow
+ if (duration > 3) {
+ System.err.println("!!!!!! Too long. Expected <1 but was " + duration);
+ }
+ }
+
+ System.out.println("\nMany instances.");
+ for (int number : range) {
+ time1 = System.nanoTime();
+ for (int i = 0; i < number; i++) {
+ dumper = new Yaml();
+ dumper.dumpAsMap(invoice);
+ }
+ time2 = System.nanoTime();
+ duration = ((time2 - time1) / 1000000) / (float) number;
+ System.out.println("Duration for r=" + number + " was " + duration + " ms/dump.");
+ // cobertura may make it very slow
+ if (duration > 3) {
+ System.err.println("!!!!!! Too long. Expected <1 but was " + duration);
+ }
+ // assertTrue("duration=" + duration, duration < 3);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/org/yaml/snakeyaml/stress/StressTest.java b/src/test/java/org/yaml/snakeyaml/stress/StressTest.java
new file mode 100644
index 0000000..299d1a3
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/stress/StressTest.java
@@ -0,0 +1,91 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.stress;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import org.yaml.snakeyaml.Invoice;
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.Constructor;
+
+public class StressTest extends TestCase {
+ String doc;
+
+ public static void main(String args[]) {
+ junit.textui.TestRunner.run(suite());
+ }
+
+ public static Test suite() {
+ return new TestSuite(StressTest.class);
+ }
+
+ public void setUp() {
+ doc = Util.getLocalResource("specification/example2_27.yaml");
+ }
+
+ public void testPerformance() {
+ long time1 = System.nanoTime();
+ new Yaml(new Constructor(Invoice.class));
+ long time2 = System.nanoTime();
+ float duration = (time2 - time1) / 1000000;
+ System.out.println("Init was " + duration + " ms.");
+
+ Yaml loader = new Yaml();
+ time1 = System.nanoTime();
+ loader.loadAs(doc, Invoice.class);
+ time2 = System.nanoTime();
+ duration = (time2 - time1) / 1000000;
+ System.out.println("\nSingle load was " + duration + " ms.");
+
+ loader = new Yaml();
+ int[] range = new int[] { 1000, 2000 /* , 4000, 8000 */};
+ System.out.println("\nOne instance.");
+ for (int number : range) {
+ time1 = System.nanoTime();
+ for (int i = 0; i < number; i++) {
+ loader.loadAs(doc, Invoice.class);
+ }
+ time2 = System.nanoTime();
+ duration = ((time2 - time1) / 1000000) / (float) number;
+ System.out.println("Duration for r=" + number + " was " + duration + " ms/load.");
+ // cobertura may make it very slow
+ if (duration > 3) {
+ System.err.println("!!!!!! Too long. Expected <1 but was " + duration);
+ }
+ // assertTrue("duration=" + duration, duration < 3);
+ }
+
+ System.out.println("\nMany instances.");
+ for (int number : range) {
+ time1 = System.nanoTime();
+ for (int i = 0; i < number; i++) {
+ loader = new Yaml();
+ loader.loadAs(doc, Invoice.class);
+ }
+ time2 = System.nanoTime();
+ duration = ((time2 - time1) / 1000000) / (float) number;
+ System.out.println("Duration for r=" + number + " was " + duration + " ms/load.");
+ // cobertura may make it very slow
+ if (duration > 3) {
+ System.err.println("!!!!!! Too long. Expected <1 but was " + duration);
+ }
+ // assertTrue("duration=" + duration, duration < 3);
+ }
+ }
+}
\ No newline at end of file
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 0000000..da0fd42
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/tokens/AliasTokenTest.java
@@ -0,0 +1,42 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.error.Mark;
+import org.yaml.snakeyaml.tokens.Token.ID;
+
+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(ID.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 0000000..472f7d2
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/tokens/AnchorTokenTest.java
@@ -0,0 +1,36 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.error.Mark;
+import org.yaml.snakeyaml.tokens.Token.ID;
+
+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(ID.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 0000000..3c96859
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/tokens/BlockEndTokenTest.java
@@ -0,0 +1,36 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.error.Mark;
+import org.yaml.snakeyaml.tokens.Token.ID;
+
+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(ID.BlockEnd, 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 0000000..651a230
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/tokens/BlockEntryTokenTest.java
@@ -0,0 +1,31 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.error.Mark;
+import org.yaml.snakeyaml.tokens.Token.ID;
+
+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(ID.BlockEntry, 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 0000000..69203d0
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/tokens/BlockSequenceStartTokenTest.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.error.Mark;
+import org.yaml.snakeyaml.tokens.Token.ID;
+
+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(ID.BlockSequenceStart, 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 0000000..f1e8ff1
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/tokens/DirectiveTokenTest.java
@@ -0,0 +1,69 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.error.Mark;
+import org.yaml.snakeyaml.tokens.Token.ID;
+
+public class DirectiveTokenTest extends TestCase {
+
+ public void testGetArguments() {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ DirectiveToken<Integer> token = new DirectiveToken<Integer>("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 ArrayList<Integer>();
+ list.add(new Integer(1));
+ try {
+ new DirectiveToken<Integer>("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 ArrayList<String>();
+ list.add("!foo");
+ list.add("!bar");
+ DirectiveToken<String> token = new DirectiveToken<String>("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 ArrayList<Integer>();
+ list.add(new Integer(1));
+ list.add(new Integer(1));
+ DirectiveToken<Integer> token = new DirectiveToken<Integer>("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<Integer> token = new DirectiveToken<Integer>("YAML", null, mark, mark);
+ assertEquals(ID.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 0000000..a6955ba
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/tokens/DocumentEndTokenTest.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.error.Mark;
+import org.yaml.snakeyaml.tokens.Token.ID;
+
+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(ID.DocumentEnd, 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 0000000..f7fa01e
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/tokens/DocumentStartTokenTest.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.error.Mark;
+import org.yaml.snakeyaml.tokens.Token.ID;
+
+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(ID.DocumentStart, 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 0000000..3293919
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/tokens/FlowEntryTokenTest.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.error.Mark;
+import org.yaml.snakeyaml.tokens.Token.ID;
+
+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(ID.FlowEntry, 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 0000000..4548552
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/tokens/FlowMappingStartTokenTest.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.error.Mark;
+import org.yaml.snakeyaml.tokens.Token.ID;
+
+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(ID.FlowMappingStart, 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 0000000..b62e6a8
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/tokens/FlowSequenceStartTokenTest.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.error.Mark;
+import org.yaml.snakeyaml.tokens.Token.ID;
+
+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(ID.FlowSequenceStart, 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 0000000..8ae19a4
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/tokens/StreamStartTokenTest.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.error.Mark;
+import org.yaml.snakeyaml.tokens.Token.ID;
+
+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(ID.StreamStart, 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 0000000..1194088
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/tokens/TagTokenTest.java
@@ -0,0 +1,63 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.error.Mark;
+import org.yaml.snakeyaml.error.YAMLException;
+import org.yaml.snakeyaml.tokens.Token.ID;
+
+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 TagTuple("!foo", "!bar"), mark, mark);
+ assertEquals("value=[!foo, !bar]", token.getArguments());
+ }
+
+ public void testNoMarks() {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ try {
+ new TagToken(new TagTuple("!foo", "!bar"), null, mark);
+ fail("Token without start mark should not be accepted.");
+ } catch (YAMLException e) {
+ assertEquals("Token requires marks.", e.getMessage());
+ }
+ try {
+ new TagToken(new TagTuple("!foo", "!bar"), mark, null);
+ fail("Token without end mark should not be accepted.");
+ } catch (YAMLException e) {
+ assertEquals("Token requires marks.", e.getMessage());
+ }
+ }
+
+ public void testNoTag() {
+ try {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ new TagToken(new TagTuple("!foo", null), mark, mark);
+ fail("Marks must be provided.");
+ } catch (NullPointerException e) {
+ assertEquals("Suffix must be provided.", 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 TagTuple("!foo", "!bar"), mark, mark);
+ assertEquals(ID.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 0000000..91fd03c
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/types/AbstractTest.java
@@ -0,0 +1,47 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+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);
+ }
+
+ protected Object getMapValue(String data, String key) {
+ Map<String, Object> 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 0000000..82ff947
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/types/BinaryTagTest.java
@@ -0,0 +1,76 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.types;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @see <a href="http://yaml.org/type/binary.html"></a>
+ */
+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() {
+ 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() {
+ byte[] binary = (byte[]) load("!!binary \"MQ==\"");
+ assertEquals(1, binary.length);
+ assertEquals((byte) '1', binary[0]);
+ }
+
+ public void testBinaryTag() {
+ 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() {
+ 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 0000000..96b2b3a
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/types/BoolTagTest.java
@@ -0,0 +1,133 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.types;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.DumperOptions.FlowStyle;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.Tag;
+import org.yaml.snakeyaml.representer.Represent;
+import org.yaml.snakeyaml.representer.Representer;
+
+/**
+ * @see <a href="http://yaml.org/type/bool.html"></a>
+ */
+public class BoolTagTest extends AbstractTest {
+ public void testBool() {
+ 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() {
+ 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() {
+ assertEquals(Boolean.TRUE, getMapValue("boolean: !!bool true", "boolean"));
+ }
+
+ public void testBoolTag() {
+ assertEquals(Boolean.TRUE,
+ getMapValue("boolean: !<tag:yaml.org,2002:bool> true", "boolean"));
+ }
+
+ public void testBoolOut() {
+ Map<String, Boolean> map = new HashMap<String, Boolean>();
+ map.put("boolean", Boolean.TRUE);
+ String output = dump(map);
+ assertTrue(output, output.contains("boolean: true"));
+ }
+
+ public void testBoolOutAsYes() {
+ Yaml yaml = new Yaml(new BoolRepresenter("YES"));
+ String output = yaml.dump(true);
+ assertEquals("YES\n", output);
+ }
+
+ /**
+ * test flow style
+ */
+ public void testBoolOutAsEmpty2() {
+ Yaml yaml = new Yaml(new BoolRepresenter("on"));
+ Map<String, Boolean> map = new HashMap<String, Boolean>();
+ map.put("aaa", false);
+ map.put("bbb", true);
+ String output = yaml.dump(map);
+ assertEquals("{aaa: false, bbb: on}\n", output);
+ }
+
+ /**
+ * test block style
+ */
+ public void testBoolOutAsEmpty3() {
+ DumperOptions options = new DumperOptions();
+ options.setDefaultFlowStyle(FlowStyle.BLOCK);
+ Yaml yaml = new Yaml(new BoolRepresenter("True"), options);
+ Map<String, Boolean> map = new HashMap<String, Boolean>();
+ map.put("aaa", false);
+ map.put("bbb", true);
+ String output = yaml.dump(map);
+ assertEquals("aaa: false\nbbb: True\n", output);
+ }
+
+ private class BoolRepresenter extends Representer {
+ private String value;
+
+ public BoolRepresenter(String value) {
+ super();
+ this.value = value;
+ this.representers.put(Boolean.class, new RepresentBool());
+ }
+
+ // possible values are here http://yaml.org/type/bool.html
+ // y, Y, n, N should not be used
+ private class RepresentBool implements Represent {
+ public Node representData(Object data) {
+ String v;
+ if (Boolean.TRUE.equals(data)) {
+ v = value;
+ } else {
+ v = "false";
+ }
+ return representScalar(Tag.BOOL, v);
+ }
+ }
+ }
+}
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 0000000..c517f66
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/types/FloatTagTest.java
@@ -0,0 +1,77 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.types;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @see <a href="http://yaml.org/type/float.html"></a>
+ */
+public class FloatTagTest extends AbstractTest {
+
+ public void testFloat() {
+ 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() {
+ assertEquals(new Double(1), getMapValue("number: !!float 1", "number"));
+ }
+
+ public void testFloatTag() {
+ assertEquals(new Double(1), getMapValue("number: !<tag:yaml.org,2002:float> 1", "number"));
+ }
+
+ public void testFloatOut() {
+ 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));
+ }
+
+ /**
+ * to test http://code.google.com/p/snakeyaml/issues/detail?id=130
+ */
+ public void testScientificFloatWithoutDecimalDot() {
+ assertEquals(new Double(8e-06), load("8e-06"));
+ assertEquals(new Double(8e06), load("8e06"));
+ assertEquals(new Double(8e06), load("8e+06"));
+ assertEquals(new Double(8000e06), load("8_000e06"));
+ assertEquals(new Double(123e-06), load("123e-06"));
+ }
+}
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 0000000..2adb9c8
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/types/IntTagTest.java
@@ -0,0 +1,65 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.types;
+
+import java.math.BigInteger;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @see <a href="http://yaml.org/type/int.html"></a>
+ */
+public class IntTagTest extends AbstractTest {
+
+ public void testInt() {
+ 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() {
+ assertEquals(new Long(922337203685477580L), load("922337203685477580"));
+ assertEquals(new BigInteger("9223372036854775809999999999"),
+ load("9223372036854775809999999999"));
+ assertEquals(Long.MIN_VALUE, load("-9223372036854775808"));
+ }
+
+ public void testIntShorthand() {
+ assertEquals(new Integer(1), getMapValue("number: !!int 1", "number"));
+ }
+
+ public void testIntTag() {
+ assertEquals(new Integer(1), getMapValue("number: !<tag:yaml.org,2002:int> 1", "number"));
+ }
+
+ public void testIntOut() {
+ 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 0000000..b6449a7
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/types/MapTagTest.java
@@ -0,0 +1,70 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.types;
+
+import java.util.Map;
+
+import org.yaml.snakeyaml.YamlDocument;
+
+/**
+ * @see <a href="http://yaml.org/type/map.html"></a>
+ */
+public class MapTagTest extends AbstractTest {
+
+ @SuppressWarnings("unchecked")
+ public void testMap() {
+ 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() {
+ 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 0000000..9af5d47
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/types/MergeTagTest.java
@@ -0,0 +1,70 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.types;
+
+import java.util.List;
+import java.util.Map;
+
+import org.yaml.snakeyaml.YamlDocument;
+
+/**
+ * @see <a href="http://yaml.org/type/merge.html"></a>
+ */
+public class MergeTagTest extends AbstractTest {
+
+ @SuppressWarnings("unchecked")
+ public void testMerge() {
+ YamlDocument document = new YamlDocument("types/merge.yaml");
+ List<Object> list = (List<Object>) 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 0000000..b3cd966
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/types/NullTagTest.java
@@ -0,0 +1,152 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.types;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.DumperOptions.FlowStyle;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.Tag;
+import org.yaml.snakeyaml.representer.Represent;
+import org.yaml.snakeyaml.representer.Representer;
+
+/**
+ * @see <a href="http://yaml.org/type/null.html"></a>
+ */
+public class NullTagTest extends AbstractTest {
+
+ public void testNull() {
+ 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() {
+ 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() {
+ 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 testNullShorthand() {
+ assertNull(getMapValue("nothing: !!null null", "nothing"));
+ }
+
+ public void testNullTag() {
+ assertNull(getMapValue("nothing: !<tag:yaml.org,2002:null> null", "nothing"));
+ }
+
+ public void testNullOut() {
+ String output = dump(null);
+ assertEquals("null\n", output);
+ }
+
+ public void testNullOutAsEmpty() {
+ Yaml yaml = new Yaml(new NullRepresenter());
+ String output = yaml.dump(null);
+ assertEquals("", output);
+ }
+
+ /**
+ * test flow style
+ */
+ public void testNullOutAsEmpty2() {
+ Yaml yaml = new Yaml(new NullRepresenter());
+ Map<String, String> map = new HashMap<String, String>();
+ map.put("aaa", "foo");
+ map.put("bbb", null);
+ String output = yaml.dump(map);
+ assertEquals("{aaa: foo, bbb: !!null ''}\n", output);
+ }
+
+ /**
+ * test block style
+ */
+ public void testBoolOutAsEmpty3() {
+ DumperOptions options = new DumperOptions();
+ options.setDefaultFlowStyle(FlowStyle.BLOCK);
+ Yaml yaml = new Yaml(new NullRepresenter(), options);
+ Map<String, String> map = new HashMap<String, String>();
+ map.put("aaa", "foo");
+ map.put("bbb", null);
+ String output = yaml.dump(map);
+ assertEquals("aaa: foo\nbbb:\n", output);
+ }
+
+ private class NullRepresenter extends Representer {
+ public NullRepresenter() {
+ super();
+ // null representer is exceptional and it is stored as an instance
+ // variable.
+ this.nullRepresenter = new RepresentNull();
+ }
+
+ private class RepresentNull implements Represent {
+ public Node representData(Object data) {
+ // possible values are here http://yaml.org/type/null.html
+ return representScalar(Tag.NULL, "");
+ }
+ }
+ }
+
+ public void testNoAnchors() {
+ List<String> list = new ArrayList<String>(3);
+ list.add(null);
+ list.add("value");
+ list.add(null);
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(list);
+ assertEquals("Null values must not get anchors and aliases.", "[null, value, 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 0000000..2811dea
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/types/OmapTagTest.java
@@ -0,0 +1,46 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.types;
+
+import java.util.Map;
+
+import org.yaml.snakeyaml.YamlDocument;
+
+/**
+ * @see <a href="http://yaml.org/type/omap.html"></a>
+ */
+public class OmapTagTest extends AbstractTest {
+
+ @SuppressWarnings("unchecked")
+ public void testOmap() {
+ 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 0000000..2f3c73e
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/types/PairsTagTest.java
@@ -0,0 +1,70 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.types;
+
+import java.util.List;
+import java.util.Map;
+
+import org.yaml.snakeyaml.YamlDocument;
+
+/**
+ * @see <a href="http://yaml.org/type/pairs.html"></a>
+ */
+public class PairsTagTest extends AbstractTest {
+
+ @SuppressWarnings("unchecked")
+ public void testPairs() {
+ 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 0000000..0f4123b
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/types/SeqTagTest.java
@@ -0,0 +1,93 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.types;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.yaml.snakeyaml.YamlDocument;
+
+/**
+ * @see <a href="http://yaml.org/type/seq.html"></a>
+ */
+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);
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testCollection() {
+ Collection<Integer> collection = new LinkedList<Integer>();
+ collection.add(1);
+ collection.add(2);
+ collection.add(3);
+ String output = dump(collection);
+ assertEquals("[1, 2, 3]\n", output);
+ Collection<Integer> obj = (Collection<Integer>) load(output);
+ // System.out.println(obj);
+ assertEquals(3, obj.size());
+ assertTrue("Create ArrayList by default: " + obj.getClass().toString(),
+ obj instanceof ArrayList);
+ }
+
+ 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 testStringArray() {
+ String[] array = new String[] { "aaa", "bbb", "ccc" };
+ String output = dump(array);
+ assertEquals("[aaa, bbb, ccc]\n", output);
+ }
+}
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 0000000..add9b59
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/types/SetTagTest.java
@@ -0,0 +1,45 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.types;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.yaml.snakeyaml.YamlDocument;
+
+/**
+ * @see <a href="http://yaml.org/type/set.html"></a>
+ */
+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 0000000..600bd5b
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/types/StrTagTest.java
@@ -0,0 +1,173 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.types;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStreamWriter;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.DumperOptions.ScalarStyle;
+import org.yaml.snakeyaml.Yaml;
+
+/**
+ * @see <a href="http://yaml.org/type/str.html"></a>
+ */
+public class StrTagTest extends AbstractTest {
+ private String getData(String data, String key) {
+ return (String) getMapValue(data, key);
+ }
+
+ public void testString() {
+ assertEquals("abcd", getData("string: abcd", "string"));
+ }
+
+ public void testStringShorthand() {
+ assertEquals("abcd", getData("string: !!str abcd", "string"));
+ }
+
+ public void testStringTag() {
+ assertEquals("abcd", getData("string: !<tag:yaml.org,2002:str> abcd", "string"));
+ }
+
+ public void testUnicode() {
+ // 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 <a href="http://code.google.com/p/jvyamlb/issues/detail?id=6"></a>
+ */
+ @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() {
+ String str = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
+ String output = dump(str);
+ assertEquals(str + "\n", output);
+ }
+
+ public void testEmitLongStringWithCR() {
+ String str = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n\n";
+ String output = dump(str);
+ assertEquals("|+\n " + str, output);
+ }
+
+ public void testEmitDoubleQuoted() {
+ String str = "\"xx\"";
+ String output = dump(str);
+ assertEquals("'" + str + "'\n", output);
+ }
+
+ /**
+ * http://pyyaml.org/ticket/196
+ */
+ public void testEmitQuoted() {
+ List<String> list = new ArrayList<String>(3);
+ list.add("This is an 'example'.");
+ list.add("This is an \"example\".");
+ list.add("123");
+ String output = dump(list);
+ assertEquals("[This is an 'example'., This is an \"example\"., '123']\n", output);
+ // single quoted
+ DumperOptions options = new DumperOptions();
+ options.setDefaultScalarStyle(ScalarStyle.SINGLE_QUOTED);
+ Yaml yaml = new Yaml(options);
+ String output2 = yaml.dump(list);
+ // System.out.println(output2);
+ assertEquals("- 'This is an ''example''.'\n- 'This is an \"example\".'\n- '123'\n", output2);
+ // double quoted
+ DumperOptions options2 = new DumperOptions();
+ options2.setDefaultScalarStyle(ScalarStyle.DOUBLE_QUOTED);
+ yaml = new Yaml(options2);
+ String output3 = yaml.dump(list);
+ // System.out.println(output2);
+ assertEquals("- \"This is an 'example'.\"\n- \"This is an \\\"example\\\".\"\n- \"123\"\n",
+ output3);
+ }
+
+ public void testEmitEndOfLine() {
+ String str = "xxxxxxx\n";
+ String output = dump(str);
+ assertEquals("|\n " + str, output);
+ }
+
+ public void testDumpUtf16() throws UnsupportedEncodingException {
+ 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 0000000..5e889d1
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/types/TimestampTagTest.java
@@ -0,0 +1,123 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.types;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.TimeZone;
+
+/**
+ * @see <a href="http://yaml.org/type/timestamp.html"></a>
+ */
+public class TimestampTagTest extends AbstractTest {
+
+ public void testTimestamp() {
+ assertEquals("2001-12-15 at 2:59:43 (100)",
+ getText("canonical: 2001-12-15T02:59:43.1Z", "canonical"));
+ // zero miliseconds
+ assertEquals("2001-12-15 at 2:59:43 (0)",
+ getText("canonical: 2001-12-15T02:59:43.000Z", "canonical"));
+ assertEquals("2001-12-15 at 2:59:43 (100)",
+ getText("valid iso8601: 2001-12-14t21:59:43.10-05:00", "valid iso8601"));
+ // half hour time zone
+ assertEquals("2001-12-14 at 22:29:43 (100)",
+ getText("valid iso8601: 2001-12-14t21:59:43.10-0:30", "valid iso8601"));
+ // + time zone
+ assertEquals("2001-12-14 at 19:59:43 (100)",
+ getText("valid iso8601: 2001-12-14t21:59:43.10+2: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)"));
+ assertEquals("2010-5-16 at 3:6:11 (3)",
+ getText("milliseconds: 2010-05-16 03:06:11.003", "milliseconds"));
+ assertEquals("2010-5-16 at 3:6:11 (7)",
+ getText("milliseconds: 2010-05-16 03:06:11.0068", "milliseconds"));
+ assertEquals("2010-5-16 at 3:6:11 (0)",
+ getText("milliseconds: 2010-05-16 03:06:11.0000", "milliseconds"));
+ assertEquals("2010-5-16 at 3:6:11 (0)",
+ getText("milliseconds: 2010-05-16 03:06:11.0004", "milliseconds"));
+ assertEquals("2010-5-16 at 3:6:11 (25)",
+ getText("milliseconds: 2010-05-16 03:06:11.0250", "milliseconds"));
+ }
+
+ public void testTimestampShorthand() {
+ assertTrue(getMapValue("canonical: !!timestamp 2001-12-15T02:59:43.1Z", "canonical") instanceof Date);
+ }
+
+ public void testTimestampTag() {
+ assertTrue(getMapValue("canonical: !<tag:yaml.org,2002:timestamp> 2001-12-15T02:59:43.1Z",
+ "canonical") instanceof Date);
+ }
+
+ public void testTimestampOut() {
+ 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() {
+ 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() {
+ 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() {
+ 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 0000000..7490b1d
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/types/ValueTagTest.java
@@ -0,0 +1,60 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.types;
+
+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 <a href="http://yaml.org/type/value.html"></a>
+ */
+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() {
+ InputStream input = YamlDocument.class.getClassLoader().getResourceAsStream(
+ YamlDocument.ROOT + "types/value.yaml");
+ Yaml yaml = new Yaml();
+ Iterator<Object> iter = (Iterator<Object>) 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/java/org/yaml/snakeyaml/util/ArrayStackTest.java b/src/test/java/org/yaml/snakeyaml/util/ArrayStackTest.java
new file mode 100644
index 0000000..dd1cebe
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/util/ArrayStackTest.java
@@ -0,0 +1,31 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.util;
+
+import junit.framework.TestCase;
+
+public class ArrayStackTest extends TestCase {
+
+ public void testClear() {
+ ArrayStack<Integer> stack = new ArrayStack<Integer>(25);
+ assertTrue(stack.isEmpty());
+ stack.push(new Integer(1));
+ stack.push(new Integer(2));
+ assertFalse(stack.isEmpty());
+ stack.clear();
+ assertTrue(stack.isEmpty());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/util/UriEncoderTest.java b/src/test/java/org/yaml/snakeyaml/util/UriEncoderTest.java
new file mode 100644
index 0000000..babf61b
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/util/UriEncoderTest.java
@@ -0,0 +1,51 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.util;
+
+import java.nio.ByteBuffer;
+import java.nio.charset.CharacterCodingException;
+
+import junit.framework.TestCase;
+
+public class UriEncoderTest extends TestCase {
+
+ public void testEncode() {
+ assertEquals("Acad%C3%A9mico", UriEncoder.encode("Académico"));
+ assertEquals("Check http://yaml.org/spec/1.1/#escaping%20in%20URI/", "[]",
+ UriEncoder.encode("[]"));
+ }
+
+ public void testDecode() throws CharacterCodingException {
+ ByteBuffer buff = ByteBuffer.allocate(10);
+ buff.put((byte) 0x34);
+ buff.put((byte) 0x35);
+ buff.flip();
+ assertEquals("45", UriEncoder.decode(buff));
+ }
+
+ public void testFailDecode() throws CharacterCodingException {
+ ByteBuffer buff = ByteBuffer.allocate(10);
+ buff.put((byte) 0x34);
+ buff.put((byte) 0xC1);
+ buff.flip();
+ try {
+ UriEncoder.decode(buff);
+ fail("Invalid UTF-8 must not be accepted.");
+ } catch (Exception e) {
+ assertEquals("Input length = 1", e.getMessage());
+ }
+ }
+}
diff --git a/src/test/java8/org/yaml/snakeyaml/issues/issue310/OptionalTest.java b/src/test/java8/org/yaml/snakeyaml/issues/issue310/OptionalTest.java
new file mode 100644
index 0000000..59322a3
--- /dev/null
+++ b/src/test/java8/org/yaml/snakeyaml/issues/issue310/OptionalTest.java
@@ -0,0 +1,158 @@
+/**
+ * Copyright (c) 2008, http://www.snakeyaml.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.yaml.snakeyaml.issues.issue310;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+import org.junit.Test;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.Tag;
+import org.yaml.snakeyaml.representer.Represent;
+import org.yaml.snakeyaml.representer.Representer;
+
+public class OptionalTest {
+
+ public static class Salary {
+
+ private Optional<Double> income = Optional.empty();
+
+ public Optional<Double> getIncome() {
+ return income;
+ }
+
+ public void setIncome(Double income) {
+ this.income = Optional.of(income);
+ }
+
+ public void setIncome(Optional<Double> income) {
+ this.income = income;
+ }
+
+ @Override
+ public String toString() {
+ return "Salary{" + "income=" + income + '}';
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result
+ + ((income == null) ? 0 : income.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ Salary other = (Salary) obj;
+ if (income == null) {
+ if (other.income != null)
+ return false;
+ } else if (!income.equals(other.income))
+ return false;
+ return true;
+ }
+ }
+
+ public static class Person {
+
+ private String name;
+
+ private Optional<Salary> salary = Optional.empty();
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Optional<Salary> getSalary() {
+ return salary;
+ }
+
+ public void setSalary(Optional<Salary> salary) {
+ this.salary = salary;
+ }
+
+ @Override
+ public String toString() {
+ return "Person{" + "name='" + name + '\'' + ", salary=" + salary
+ + '}';
+ }
+ }
+
+ public static class OptionalRepresenter extends Representer {
+ public OptionalRepresenter() {
+ this.representers.put(Optional.class, new RepresentOptional());
+ }
+
+ private class RepresentOptional implements Represent {
+
+ public Node representData(Object data) {
+ Optional<?> opt = (Optional<?>) data;
+ List<Object> seq = new ArrayList<>(1);
+ seq.add(opt.get());
+ return representSequence(Tag.SEQ, seq, true);
+ }
+ }
+ }
+
+ @Test
+ public void testOptionaStringLoad() {
+ final String yamlStr = "name: Neo Anderson\nsalary: [{income: [123456.78]}]\n";
+ final Yaml yamlParser = new Yaml(new OptionalRepresenter());
+ Person expectedPerson = new Person();
+ Salary s = new Salary();
+ s.setIncome(123456.78);
+ expectedPerson.setName("Neo Anderson");
+ expectedPerson.setSalary(Optional.of(s));
+
+ final Person pFromStr = yamlParser.loadAs(yamlStr, Person.class);
+
+ assertEquals(expectedPerson.getName(), pFromStr.getName());
+ assertEquals(expectedPerson.getSalary(), pFromStr.getSalary());
+ }
+
+ @Test
+ public void testOptionalDumpLoad() {
+ final Yaml yamlParser = new Yaml(new OptionalRepresenter());
+ Person expectedPerson = new Person();
+ Salary s = new Salary();
+ s.setIncome(123456.78);
+ expectedPerson.setName("Neo Anderson");
+ expectedPerson.setSalary(Optional.of(s));
+
+ String pDump = yamlParser.dump(expectedPerson);
+ // System.out.println(pDump);
+ final Person pFromDump = yamlParser.loadAs(pDump, Person.class);
+
+ assertEquals(expectedPerson.getName(), pFromDump.getName());
+ assertEquals(expectedPerson.getSalary(), pFromDump.getSalary());
+ }
+}
diff --git a/src/test/resources/compactnotation/error1.yaml b/src/test/resources/compactnotation/error1.yaml
new file mode 100644
index 0000000..1107bc9
--- /dev/null
+++ b/src/test/resources/compactnotation/error1.yaml
@@ -0,0 +1,2 @@
+Table(id12, A table)
+
diff --git a/src/test/resources/compactnotation/error2.yaml b/src/test/resources/compactnotation/error2.yaml
new file mode 100644
index 0000000..2f3fa3e
--- /dev/null
+++ b/src/test/resources/compactnotation/error2.yaml
@@ -0,0 +1,2 @@
+Table(id12)
+
diff --git a/src/test/resources/compactnotation/error3.yaml b/src/test/resources/compactnotation/error3.yaml
new file mode 100644
index 0000000..c97fa44
--- /dev/null
+++ b/src/test/resources/compactnotation/error3.yaml
@@ -0,0 +1,2 @@
+Table(id12, orders):
+ - Row(id111, size=17, description=text)
diff --git a/src/test/resources/compactnotation/error4.yaml b/src/test/resources/compactnotation/error4.yaml
new file mode 100644
index 0000000..0cd4995
--- /dev/null
+++ b/src/test/resources/compactnotation/error4.yaml
@@ -0,0 +1,4 @@
+Table(id12, table):
+ - Row(id111, description = text) {size: 15}
+
+
diff --git a/src/test/resources/compactnotation/error5.yaml b/src/test/resources/compactnotation/error5.yaml
new file mode 100644
index 0000000..68c081d
--- /dev/null
+++ b/src/test/resources/compactnotation/error5.yaml
@@ -0,0 +1,11 @@
+Table(id12, table):
+ - Row(id222):
+ size: 17
+ ratio: 0.333
+ description: >
+ We do not need new lines
+ here, just replace them
+ all with spaces
+
+
+
diff --git a/src/test/resources/compactnotation/error6.yaml b/src/test/resources/compactnotation/error6.yaml
new file mode 100644
index 0000000..f17ecfb
--- /dev/null
+++ b/src/test/resources/compactnotation/error6.yaml
@@ -0,0 +1,4 @@
+Table(id12, table, foo=bar)
+
+
+
diff --git a/src/test/resources/compactnotation/error7.yaml b/src/test/resources/compactnotation/error7.yaml
new file mode 100644
index 0000000..bf0f8c0
--- /dev/null
+++ b/src/test/resources/compactnotation/error7.yaml
@@ -0,0 +1,5 @@
+Table(id12, table):
+ foo: bar
+
+
+
diff --git a/src/test/resources/compactnotation/error8.yaml b/src/test/resources/compactnotation/error8.yaml
new file mode 100644
index 0000000..382d5e4
--- /dev/null
+++ b/src/test/resources/compactnotation/error8.yaml
@@ -0,0 +1,11 @@
+Row(id12):
+ - Row(id222):
+ size: 17
+ ratio: 0.333
+ description: >
+ We do not need new lines
+ here, just replace them
+ all with spaces
+
+
+
diff --git a/src/test/resources/compactnotation/error9.yaml b/src/test/resources/compactnotation/error9.yaml
new file mode 100644
index 0000000..d8a3ae9
--- /dev/null
+++ b/src/test/resources/compactnotation/error9.yaml
@@ -0,0 +1,11 @@
+ManyListsTable(id12):
+ - Row(id111, description = text)
+ - Row(id222):
+ size: 17
+ ratio: 0.333
+ description: >
+ We do not need new lines
+ here, just replace them
+ all with spaces
+
+
diff --git a/src/test/resources/compactnotation/example1.yaml b/src/test/resources/compactnotation/example1.yaml
new file mode 100644
index 0000000..c6a6ae5
--- /dev/null
+++ b/src/test/resources/compactnotation/example1.yaml
@@ -0,0 +1 @@
+org.yaml.snakeyaml.extensions.compactnotation.Container(name=parent, id=123)
diff --git a/src/test/resources/compactnotation/example10.yaml b/src/test/resources/compactnotation/example10.yaml
new file mode 100644
index 0000000..03b94c2
--- /dev/null
+++ b/src/test/resources/compactnotation/example10.yaml
@@ -0,0 +1,5 @@
+something:
+ - org.yaml.snakeyaml.extensions.compactnotation.Container(t7, id=id7): { name: child7 }
+ - org.yaml.snakeyaml.extensions.compactnotation.Container(t9, id=id9): { name: child9 }
+ - org.yaml.snakeyaml.extensions.compactnotation.Container(t10, id=id10): { name: child10 }
+
diff --git a/src/test/resources/compactnotation/example11.yaml b/src/test/resources/compactnotation/example11.yaml
new file mode 100644
index 0000000..6b09d2d
--- /dev/null
+++ b/src/test/resources/compactnotation/example11.yaml
@@ -0,0 +1,4 @@
+Box(id11, Main box):
+ top: Item(id003, price=25.0, name=parrot)
+ bottom: Item(id004, price=3.5, name=sweet)
+
diff --git a/src/test/resources/compactnotation/example12.yaml b/src/test/resources/compactnotation/example12.yaml
new file mode 100644
index 0000000..15a14f2
--- /dev/null
+++ b/src/test/resources/compactnotation/example12.yaml
@@ -0,0 +1,19 @@
+Table(id12, A table):
+ - Row(id111, description = I think; therefore I am.): {size: 15, ratio: 0.125}
+ - Row(id222):
+ size: 17
+ ratio: 0.333
+ floatRatio: 0.333
+ description: >
+ We do not need new lines
+ here, just replace them
+ all with spaces
+ - Row(id333):
+ size: 52
+ ratio: 0.88
+ floatRatio: 0.88
+ description: |-
+ Please preserve all
+ the lines because they may be
+ important, but do not include the last one !!!
+
diff --git a/src/test/resources/compactnotation/example2.yaml b/src/test/resources/compactnotation/example2.yaml
new file mode 100644
index 0000000..6105cd0
--- /dev/null
+++ b/src/test/resources/compactnotation/example2.yaml
@@ -0,0 +1 @@
+org.yaml.snakeyaml.extensions.compactnotation.Container(title)
diff --git a/src/test/resources/compactnotation/example3.yaml b/src/test/resources/compactnotation/example3.yaml
new file mode 100644
index 0000000..e240c76
--- /dev/null
+++ b/src/test/resources/compactnotation/example3.yaml
@@ -0,0 +1 @@
+org.yaml.snakeyaml.extensions.compactnotation.Container(title3, name=parent, id=123)
\ No newline at end of file
diff --git a/src/test/resources/compactnotation/example4.yaml b/src/test/resources/compactnotation/example4.yaml
new file mode 100644
index 0000000..3c3f25f
--- /dev/null
+++ b/src/test/resources/compactnotation/example4.yaml
@@ -0,0 +1,2 @@
+org.yaml.snakeyaml.extensions.compactnotation.Container(title4, name=parent4, id=444):
+ name: child4
diff --git a/src/test/resources/compactnotation/example5.yaml b/src/test/resources/compactnotation/example5.yaml
new file mode 100644
index 0000000..21dd668
--- /dev/null
+++ b/src/test/resources/compactnotation/example5.yaml
@@ -0,0 +1,4 @@
+org.yaml.snakeyaml.extensions.compactnotation.Container(title4):
+ name: child5
+ id: ID555
+
diff --git a/src/test/resources/compactnotation/example6.yaml b/src/test/resources/compactnotation/example6.yaml
new file mode 100644
index 0000000..e29f097
--- /dev/null
+++ b/src/test/resources/compactnotation/example6.yaml
@@ -0,0 +1,2 @@
+org.yaml.snakeyaml.extensions.compactnotation.Container(title4): { name: child6, id: ID6}
+
diff --git a/src/test/resources/compactnotation/example7.yaml b/src/test/resources/compactnotation/example7.yaml
new file mode 100644
index 0000000..86dd082
--- /dev/null
+++ b/src/test/resources/compactnotation/example7.yaml
@@ -0,0 +1,2 @@
+org.yaml.snakeyaml.extensions.compactnotation.Container(The title, id=id7): { name: child7 }
+
diff --git a/src/test/resources/compactnotation/example9.yaml b/src/test/resources/compactnotation/example9.yaml
new file mode 100644
index 0000000..3dd6e6f
--- /dev/null
+++ b/src/test/resources/compactnotation/example9.yaml
@@ -0,0 +1,4 @@
+something:
+ org.yaml.snakeyaml.extensions.compactnotation.Container(t7, id=id7): { name: child7 }
+ org.yaml.snakeyaml.extensions.compactnotation.Container(t9, id=id9): { name: child9 }
+
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 0000000..7677d1b
--- /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 0000000..9fcc390
--- /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 0000000..886c55b
--- /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 0000000..852a888
--- /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 0000000..6f515c5
--- /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-flow-auto.yaml b/src/test/resources/constructor/cararray-with-tags-flow-auto.yaml
new file mode 100644
index 0000000..b658266
--- /dev/null
+++ b/src/test/resources/constructor/cararray-with-tags-flow-auto.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/cararray-with-tags.yaml b/src/test/resources/constructor/cararray-with-tags.yaml
new file mode 100644
index 0000000..0ee6472
--- /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 0000000..f5eb144
--- /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 0000000..59fdc76
--- /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 0000000..5e2c948
--- /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 0000000..b5092ee
--- /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/list-bean-1.yaml b/src/test/resources/examples/list-bean-1.yaml
new file mode 100644
index 0000000..124a4af
--- /dev/null
+++ b/src/test/resources/examples/list-bean-1.yaml
@@ -0,0 +1,9 @@
+children:
+- aaa
+- bbb
+developers:
+- name: Fred
+ role: creator
+- name: John
+ role: committer
+name: Bean123
diff --git a/src/test/resources/examples/list-bean-2.yaml b/src/test/resources/examples/list-bean-2.yaml
new file mode 100644
index 0000000..82cd9f6
--- /dev/null
+++ b/src/test/resources/examples/list-bean-2.yaml
@@ -0,0 +1,12 @@
+children:
+- aaa
+- bbb
+developers:
+- !!examples.collections.TypeSafeListWithInterfaceTest$Developer
+ name: Fred
+ role: creator
+- !!examples.collections.TypeSafeListWithInterfaceTest$Committer
+ key: 34
+ name: John
+ role: committer
+name: Bean123
\ No newline at end of file
diff --git a/src/test/resources/examples/list-bean-3.yaml b/src/test/resources/examples/list-bean-3.yaml
new file mode 100644
index 0000000..d2ffdac
--- /dev/null
+++ b/src/test/resources/examples/list-bean-3.yaml
@@ -0,0 +1,6 @@
+developers:
+- name: Fred
+ role: creator
+- name: John
+ role: committer
+name: Bean123
diff --git a/src/test/resources/examples/list-bean-4.yaml b/src/test/resources/examples/list-bean-4.yaml
new file mode 100644
index 0000000..518e2d3
--- /dev/null
+++ b/src/test/resources/examples/list-bean-4.yaml
@@ -0,0 +1,12 @@
+children:
+- aaa
+- bbb
+developers:
+- !!examples.collections.TypeSafeListNoGerericsTest$Developer
+ name: Fred
+ role: creator
+- !!examples.collections.TypeSafeListNoGerericsTest$Developer
+ name: John
+ role: committer
+name: Bean123
+
diff --git a/src/test/resources/examples/map-bean-1.yaml b/src/test/resources/examples/map-bean-1.yaml
new file mode 100644
index 0000000..a8e9eb1
--- /dev/null
+++ b/src/test/resources/examples/map-bean-1.yaml
@@ -0,0 +1,7 @@
+name: Bean123
+properties:
+ key2: value2
+ key1: value1
+sorted:
+ '1': one
+ '2': two
\ No newline at end of file
diff --git a/src/test/resources/examples/map-bean-10.yaml b/src/test/resources/examples/map-bean-10.yaml
new file mode 100644
index 0000000..c26c79e
--- /dev/null
+++ b/src/test/resources/examples/map-bean-10.yaml
@@ -0,0 +1,12 @@
+data:
+ aaa: 1
+ bbb: 2
+ zzz: 3
+developers:
+ team1:
+ name: Fred
+ role: creator
+ team2:
+ name: John
+ role: committer
+name: Bean123
diff --git a/src/test/resources/examples/map-bean-11.yaml b/src/test/resources/examples/map-bean-11.yaml
new file mode 100644
index 0000000..24fe91d
--- /dev/null
+++ b/src/test/resources/examples/map-bean-11.yaml
@@ -0,0 +1,15 @@
+data:
+ aaa: 1
+ bbb: 2
+developers:
+ team1:
+ name: Fred
+ role: creator
+ team2:
+ name: John
+ role: committer
+ team3: !!examples.collections.TypeSafeMapTest$Developer222
+ name: Bill
+ role: head
+name: Bean123
+
diff --git a/src/test/resources/examples/map-bean-12.yaml b/src/test/resources/examples/map-bean-12.yaml
new file mode 100644
index 0000000..feb5a85
--- /dev/null
+++ b/src/test/resources/examples/map-bean-12.yaml
@@ -0,0 +1,16 @@
+data:
+ ? name: Andy
+ role: tester
+ : BLACK
+ ? name: Lisa
+ role: owner
+ : RED
+developers:
+ WHITE:
+ name: Fred
+ role: creator
+ BLACK:
+ name: John
+ role: committer
+name: Bean123
+
diff --git a/src/test/resources/examples/map-bean-13.yaml b/src/test/resources/examples/map-bean-13.yaml
new file mode 100644
index 0000000..17974ce
--- /dev/null
+++ b/src/test/resources/examples/map-bean-13.yaml
@@ -0,0 +1,25 @@
+data:
+ ? name: Andy
+ role: tester
+ : BLACK
+ ? !!examples.collections.TypeSafeMap2Test$SuperMan
+ name: Bill
+ role: cleaner
+ smart: false
+ : BLACK
+ ? name: Lisa
+ role: owner
+ : RED
+developers:
+ WHITE:
+ name: Fred
+ role: creator
+ RED: !!examples.collections.TypeSafeMap2Test$SuperMan
+ name: Jason
+ role: contributor
+ smart: true
+ BLACK:
+ name: John
+ role: committer
+name: Bean123
+
diff --git a/src/test/resources/examples/map-bean-2.yaml b/src/test/resources/examples/map-bean-2.yaml
new file mode 100644
index 0000000..742792d
--- /dev/null
+++ b/src/test/resources/examples/map-bean-2.yaml
@@ -0,0 +1,3 @@
+- {'1': one, '2': two}
+- {key2: value2, key1: value1}
+- aaa
diff --git a/src/test/resources/examples/map-recursive-1.yaml b/src/test/resources/examples/map-recursive-1.yaml
new file mode 100644
index 0000000..6352266
--- /dev/null
+++ b/src/test/resources/examples/map-recursive-1.yaml
@@ -0,0 +1,4 @@
+&id001
+'1': one
+'2': two
+'3': *id001
diff --git a/src/test/resources/examples/map-recursive-1_1.yaml b/src/test/resources/examples/map-recursive-1_1.yaml
new file mode 100644
index 0000000..8830184
--- /dev/null
+++ b/src/test/resources/examples/map-recursive-1_1.yaml
@@ -0,0 +1,4 @@
+&id001
+'2': two
+'1': one
+'3': *id001
diff --git a/src/test/resources/examples/map-recursive-2.yaml b/src/test/resources/examples/map-recursive-2.yaml
new file mode 100644
index 0000000..3b582d4
--- /dev/null
+++ b/src/test/resources/examples/map-recursive-2.yaml
@@ -0,0 +1,4 @@
+&id001
+key3: *id001
+key2: value2
+key1: value1
diff --git a/src/test/resources/examples/map-recursive-3.yaml b/src/test/resources/examples/map-recursive-3.yaml
new file mode 100644
index 0000000..0d58727
--- /dev/null
+++ b/src/test/resources/examples/map-recursive-3.yaml
@@ -0,0 +1,4 @@
+&id001 !!java.util.SortedMap
+'2': two
+'1': one
+'3': *id001
diff --git a/src/test/resources/examples/map-recursive-4.yaml b/src/test/resources/examples/map-recursive-4.yaml
new file mode 100644
index 0000000..217ab88
--- /dev/null
+++ b/src/test/resources/examples/map-recursive-4.yaml
@@ -0,0 +1,4 @@
+&id001 !!java.util.Properties
+key3: *id001
+key2: value2
+key1: value1
diff --git a/src/test/resources/examples/set-bean-1.yaml b/src/test/resources/examples/set-bean-1.yaml
new file mode 100644
index 0000000..82c174e
--- /dev/null
+++ b/src/test/resources/examples/set-bean-1.yaml
@@ -0,0 +1,12 @@
+developers: !!set
+ ? name: John
+ role: founder
+ : null
+ ? name: Karl
+ role: user
+ : null
+name: Bean123
+sorted: !!set
+ one: null
+ three: null
+ two: null
\ No newline at end of file
diff --git a/src/test/resources/examples/set-bean-2.yaml b/src/test/resources/examples/set-bean-2.yaml
new file mode 100644
index 0000000..3d219e2
--- /dev/null
+++ b/src/test/resources/examples/set-bean-2.yaml
@@ -0,0 +1,14 @@
+developers: !!set
+ ? name: Karl
+ role: user
+ : null
+ ? name: John
+ role: founder
+ : null
+
+name: Bean123
+
+sorted: !!set
+ two: null
+ one: null
+ three: null
\ No newline at end of file
diff --git a/src/test/resources/examples/set-bean-3.yaml b/src/test/resources/examples/set-bean-3.yaml
new file mode 100644
index 0000000..9d27d23
--- /dev/null
+++ b/src/test/resources/examples/set-bean-3.yaml
@@ -0,0 +1,7 @@
+&id001 !!set
+? !!examples.collections.TypeSafeSetImplementationsTest$Box
+ id: id123
+ set: *id001
+: null
+111: null
+aaa: null
diff --git a/src/test/resources/examples/set-bean-4.yaml b/src/test/resources/examples/set-bean-4.yaml
new file mode 100644
index 0000000..1e45b8b
--- /dev/null
+++ b/src/test/resources/examples/set-bean-4.yaml
@@ -0,0 +1 @@
+!!set {bbb: null, aaa: null, zzz: null}
\ No newline at end of file
diff --git a/src/test/resources/examples/set-bean-5.yaml b/src/test/resources/examples/set-bean-5.yaml
new file mode 100644
index 0000000..9cdba4f
--- /dev/null
+++ b/src/test/resources/examples/set-bean-5.yaml
@@ -0,0 +1 @@
+!!java.util.SortedSet {zzz: null, aaa: null, bbb: null}
\ No newline at end of file
diff --git a/src/test/resources/examples/set-bean-6.yaml b/src/test/resources/examples/set-bean-6.yaml
new file mode 100644
index 0000000..2a5243c
--- /dev/null
+++ b/src/test/resources/examples/set-bean-6.yaml
@@ -0,0 +1,16 @@
+developers: !!set
+ ? !!examples.collections.TypeSafeSetImplementationsTest$SuperDeveloper
+ name: Bill
+ role: super
+ : null
+ ? name: John
+ role: founder
+ : null
+ ? name: Karl
+ role: user
+ : null
+name: Bean123
+sorted: !!set
+ one: null
+ three: null
+ two: null
\ No newline at end of file
diff --git a/src/test/resources/examples/spring.xml b/src/test/resources/examples/spring.xml
new file mode 100644
index 0000000..66a3ad6
--- /dev/null
+++ b/src/test/resources/examples/spring.xml
@@ -0,0 +1,30 @@
+<?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="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="snakeYaml" class="org.yaml.snakeyaml.Yaml" scope="prototype">
+ <constructor-arg ref="yamlConstructor" />
+ <constructor-arg ref="yamlRepresenter" />
+ <constructor-arg ref="yamlOptions" />
+ </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="javabeanYaml" class="org.yaml.snakeyaml.Yaml" scope="prototype">
+ <constructor-arg ref="beanConstructor" />
+ </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/examples/unknown-tags-example.yaml b/src/test/resources/examples/unknown-tags-example.yaml
new file mode 100644
index 0000000..7177a58
--- /dev/null
+++ b/src/test/resources/examples/unknown-tags-example.yaml
@@ -0,0 +1,8 @@
+--- !Foo
+aaa: !Bar1 123
+bbb: !Bar2
+- 111
+- ddd
+ccc: !Bar3
+ x: !!float 1
+ y: 3.1416
diff --git a/src/test/resources/immutable/shape1.yaml b/src/test/resources/immutable/shape1.yaml
new file mode 100644
index 0000000..1ab581f
--- /dev/null
+++ b/src/test/resources/immutable/shape1.yaml
@@ -0,0 +1,9 @@
+!!org.yaml.snakeyaml.immutable.Shape
+color: BLACK
+point:
+- 1.17
+- 3.14
+point3d: !!org.yaml.snakeyaml.immutable.Point3d
+ - !!org.yaml.snakeyaml.immutable.Point [1.17, 3.14]
+ - 345.1
+id: 123
\ No newline at end of file
diff --git a/src/test/resources/immutable/shapeNoTags.yaml b/src/test/resources/immutable/shapeNoTags.yaml
new file mode 100644
index 0000000..1917739
--- /dev/null
+++ b/src/test/resources/immutable/shapeNoTags.yaml
@@ -0,0 +1,8 @@
+color: BLACK
+point:
+- 1.17
+- 3.14
+point3d:
+ - [1.96, 1.78]
+ - 345.1
+id: 123
\ No newline at end of file
diff --git a/src/test/resources/issues/ios_emoji_surrogate.yaml b/src/test/resources/issues/ios_emoji_surrogate.yaml
new file mode 100644
index 0000000..902ca7d
--- /dev/null
+++ b/src/test/resources/issues/ios_emoji_surrogate.yaml
@@ -0,0 +1 @@
+text: "😷😊"
\ No newline at end of file
diff --git a/src/test/resources/issues/issue100-1.yaml b/src/test/resources/issues/issue100-1.yaml
new file mode 100644
index 0000000..78080e0
--- /dev/null
+++ b/src/test/resources/issues/issue100-1.yaml
@@ -0,0 +1,20 @@
+- !!org.yaml.snakeyaml.issues.issue100.Data
+ &id001
+ id: id123
+ age: 11
+- !!org.yaml.snakeyaml.issues.issue100.Data
+ <<: *id001
+ id: id456
+ age: 13
+- !!org.yaml.snakeyaml.issues.issue100.Data
+ &id003
+ <<: *id001
+ id: id789
+- !!org.yaml.snakeyaml.issues.issue100.DataMore
+ <<: *id001
+ age: 30
+ complete: true
+- &id004
+ age: 100
+- !!org.yaml.snakeyaml.issues.issue100.DataMore
+ <<: [*id004, *id003]
diff --git a/src/test/resources/issues/issue100-2.yaml b/src/test/resources/issues/issue100-2.yaml
new file mode 100644
index 0000000..d6183a3
--- /dev/null
+++ b/src/test/resources/issues/issue100-2.yaml
@@ -0,0 +1,29 @@
+---
+input:
+ - &CENTER { x: 1, y: 2 }
+ - &LEFT { x: 0, y: 2 }
+ - &BIG { r: 10 }
+ - &SMALL { r: 1 }
+
+# All the following maps are equal:
+result:
+ - # Explicit keys
+ x: 1
+ y: 2
+ r: 10
+ label: center/big
+
+ - # Merge one map
+ << : *CENTER
+ r: 10
+ label: center/big
+
+ - !!map # Merge multiple maps
+ !!merge ignore: [ *CENTER, *BIG ]
+ label: center/big
+
+ - # Override
+ << : [ *BIG, *LEFT, *SMALL ]
+ x: 1
+ label: center/big
+
diff --git a/src/test/resources/issues/issue100-3.yaml b/src/test/resources/issues/issue100-3.yaml
new file mode 100644
index 0000000..9799c03
--- /dev/null
+++ b/src/test/resources/issues/issue100-3.yaml
@@ -0,0 +1,4 @@
+data: &001 {age: 17, id: id002}
+id: id001
+more: {<<: *001, id: more003, complete: true}
+
diff --git a/src/test/resources/issues/issue103.yaml b/src/test/resources/issues/issue103.yaml
new file mode 100644
index 0000000..9ff412c
--- /dev/null
+++ b/src/test/resources/issues/issue103.yaml
@@ -0,0 +1,35 @@
+---
+input:
+ - &CENTER { x: 1, y: 2 }
+ - &LEFT { x: 0, y: 2 }
+ - &BIG { r: 10 }
+ - &SMALL { r: 1 }
+
+# All the following maps are equal:
+result:
+ - # Explicit keys
+ x: 1
+ y: 2
+ r: 10
+ label: center/big
+
+ - # Merge one map
+ << : *CENTER
+ r: 10
+ label: center/big
+
+ - # Merge one map and override
+ << : *LEFT
+ y: 5
+ r: 10
+ label: center/big
+
+ - !!map # Merge multiple maps
+ !!merge ignore: [ *CENTER, *BIG ]
+ label: center/big
+
+ - # Override
+ << : [ *BIG, *LEFT, *SMALL ]
+ x: 1
+ label: center/big
+
diff --git a/src/test/resources/issues/issue112-1.yaml b/src/test/resources/issues/issue112-1.yaml
new file mode 100644
index 0000000..1866763
--- /dev/null
+++ b/src/test/resources/issues/issue112-1.yaml
@@ -0,0 +1,6 @@
+things:
+ - name: 1
+ - name: two
+ - name: 3
+ - name: four
+ - name: "!!!"
\ No newline at end of file
diff --git a/src/test/resources/issues/issue112-2.yaml b/src/test/resources/issues/issue112-2.yaml
new file mode 100644
index 0000000..4aef51b
--- /dev/null
+++ b/src/test/resources/issues/issue112-2.yaml
@@ -0,0 +1,6 @@
+things:
+- name: 1
+- name: two
+- name: 3
+- name: four
+- name: '!!!'
\ No newline at end of file
diff --git a/src/test/resources/issues/issue139-1.yaml b/src/test/resources/issues/issue139-1.yaml
new file mode 100644
index 0000000..098e9fc
--- /dev/null
+++ b/src/test/resources/issues/issue139-1.yaml
@@ -0,0 +1,6 @@
+common: &id_common
+ key1: 1
+ key2: 2
+
+production:
+ <<: *id_common
\ No newline at end of file
diff --git a/src/test/resources/issues/issue139-2.yaml b/src/test/resources/issues/issue139-2.yaml
new file mode 100644
index 0000000..ca2967c
--- /dev/null
+++ b/src/test/resources/issues/issue139-2.yaml
@@ -0,0 +1,6 @@
+common: &id_common
+ key: 1
+ key: 2 # this value must overwrite the previous. Is it specified ?
+
+production:
+ <<: *id_common
\ No newline at end of file
diff --git a/src/test/resources/issues/issue139-3.yaml b/src/test/resources/issues/issue139-3.yaml
new file mode 100644
index 0000000..3b5d0d9
--- /dev/null
+++ b/src/test/resources/issues/issue139-3.yaml
@@ -0,0 +1,7 @@
+common: &id_common
+ key: 1
+ key: 2
+
+production:
+ <<: *id_common
+ key: 3 # this value must stay
\ No newline at end of file
diff --git a/src/test/resources/issues/issue149-losing-directives-2.yaml b/src/test/resources/issues/issue149-losing-directives-2.yaml
new file mode 100644
index 0000000..3c61376
--- /dev/null
+++ b/src/test/resources/issues/issue149-losing-directives-2.yaml
@@ -0,0 +1,10 @@
+%YAML 1.1
+%TAG !u! tag:ualberta.ca,2012:
+--- !u!29 &1
+property1: 0
+property2: aaa
+...
+%TAG !second! tag:ualberta.ca,2012:
+--- !second!29 &2
+property1: 3
+property2: bbb
diff --git a/src/test/resources/issues/issue149-losing-directives.yaml b/src/test/resources/issues/issue149-losing-directives.yaml
new file mode 100644
index 0000000..db0885c
--- /dev/null
+++ b/src/test/resources/issues/issue149-losing-directives.yaml
@@ -0,0 +1,9 @@
+%YAML 1.1
+%TAG !u! tag:ualberta.ca,2012:
+--- !u!29 &1
+property1: 0
+property2: aaa
+
+--- !u!29 &2
+property1: 3
+property2: bbb
diff --git a/src/test/resources/issues/issue149-one-document.yaml b/src/test/resources/issues/issue149-one-document.yaml
new file mode 100644
index 0000000..cd45999
--- /dev/null
+++ b/src/test/resources/issues/issue149-one-document.yaml
@@ -0,0 +1,7 @@
+%YAML 1.1
+%TAG !u! tag:ualberta.ca,2012:
+--- !u!29 &1
+property1: 0
+property2: aaa
+
+
diff --git a/src/test/resources/issues/issue177-1.yaml b/src/test/resources/issues/issue177-1.yaml
new file mode 100644
index 0000000..e5975aa
--- /dev/null
+++ b/src/test/resources/issues/issue177-1.yaml
@@ -0,0 +1,8 @@
+!!org.yaml.snakeyaml.issues.issue177.Points
+points:
+ pt1:
+ x: 1
+ y: 2
+ pt2:
+ x: a
+ y: 4
diff --git a/src/test/resources/issues/issue24-1.yaml b/src/test/resources/issues/issue24-1.yaml
new file mode 100644
index 0000000..e9b4a6f
--- /dev/null
+++ b/src/test/resources/issues/issue24-1.yaml
@@ -0,0 +1,4 @@
+pop : {
+ banana: coconut
+ peppery: salty
+ }
diff --git a/src/test/resources/issues/issue306-1.yaml b/src/test/resources/issues/issue306-1.yaml
new file mode 100644
index 0000000..eb237d6
--- /dev/null
+++ b/src/test/resources/issues/issue306-1.yaml
@@ -0,0 +1,2 @@
+value: 14
+id: 7f511847-781a-45df-9c8d-1e32e028b9b3
diff --git a/src/test/resources/issues/issue306-2.yaml b/src/test/resources/issues/issue306-2.yaml
new file mode 100644
index 0000000..6bd4916
--- /dev/null
+++ b/src/test/resources/issues/issue306-2.yaml
@@ -0,0 +1,2 @@
+id: !!java.util.UUID 'ac4877be-0c31-4458-a86e-0272efe1aaa8'
+value: 3
diff --git a/src/test/resources/issues/issue55_1.txt b/src/test/resources/issues/issue55_1.txt
new file mode 100644
index 0000000..58fbf98
--- /dev/null
+++ b/src/test/resources/issues/issue55_1.txt
@@ -0,0 +1,5 @@
+posts:
+- text: Dummy
+ title: Test
+- text: Creative
+ title: Highly
\ No newline at end of file
diff --git a/src/test/resources/issues/issue55_1_rootTag.txt b/src/test/resources/issues/issue55_1_rootTag.txt
new file mode 100644
index 0000000..f073468
--- /dev/null
+++ b/src/test/resources/issues/issue55_1_rootTag.txt
@@ -0,0 +1,4 @@
+!!org.yaml.snakeyaml.issues.issue55.Blog
+posts:
+- {text: Dummy, title: Test}
+- {text: Creative, title: Highly}
\ No newline at end of file
diff --git a/src/test/resources/issues/issue55_2.txt b/src/test/resources/issues/issue55_2.txt
new file mode 100644
index 0000000..d5e6e85
--- /dev/null
+++ b/src/test/resources/issues/issue55_2.txt
@@ -0,0 +1,5 @@
+posts:
+- 1
+- 2
+- 3
+- 4
\ No newline at end of file
diff --git a/src/test/resources/issues/issue56-1.yaml b/src/test/resources/issues/issue56-1.yaml
new file mode 100644
index 0000000..e23c153
--- /dev/null
+++ b/src/test/resources/issues/issue56-1.yaml
@@ -0,0 +1,830 @@
+--- !de.oddb.org,2007/ODDB::Drugs::Product
+oid: 1724265
+name: !de.oddb.org,2007/ODDB::Util::Multilingual
+ canonical:
+ :de: ARGATRA MITSUBISHI
+ synonyms: []
+
+company: !de.oddb.org,2007/ODDB::Business::Company
+ oid: 1724276
+ name: !de.oddb.org,2007/ODDB::Util::Multilingual
+ canonical:
+ :de: Mitsubishi Ph Dt. GmbH
+ synonyms: []
+
+sequences:
+- !de.oddb.org,2007/ODDB::Drugs::Sequence
+ oid: 1724267
+ codes: []
+
+ data_origins:
+ :substance: zdavatz@ywesee.com
+ :atc: zdavatz@ywesee.com
+ :registration: zdavatz@ywesee.com
+ fachinfo_url: http://gripsdb.dimdi.de/amispb/doc/2162085-20050615/OBFM086D979C01C570B0.rtf
+ name: !de.oddb.org,2007/ODDB::Util::Multilingual
+ canonical: {}
+
+ synonyms: []
+
+ patinfo_url: http://gripsdb.dimdi.de/amispb/doc/2162085-20050615/OBFM6D3DDEAF01C570D8.rtf
+ atc: !de.oddb.org,2007/ODDB::Drugs::Atc
+ oid: 2250
+ code: B01AE03
+ name: !de.oddb.org,2007/ODDB::Util::Multilingual
+ canonical:
+ :en: Argatroban
+ :de: Argatroban
+ synonyms: []
+
+ compositions:
+ - !de.oddb.org,2007/ODDB::Drugs::Composition
+ oid: 1724261
+ active_agents:
+ - !de.oddb.org,2007/ODDB::Drugs::ActiveAgent
+ oid: 1724263
+ dose: !de.oddb.org,2007/ODDB::Drugs::Dose
+ val: 250
+ unit: mg
+ substance: !de.oddb.org,2007/ODDB::Drugs::Substance
+ oid: 1724260
+ codes: []
+
+ name: !de.oddb.org,2007/ODDB::Util::Multilingual
+ canonical:
+ :de: Argatroban
+ synonyms: []
+
+ parts:
+ - &id002 !de.oddb.org,2007/ODDB::Drugs::Part
+ oid: 1724270
+ multi:
+ quantity:
+ size: 1
+ unit: &id001 !de.oddb.org,2007/ODDB::Drugs::Unit
+ oid: 19094
+ name: !de.oddb.org,2007/ODDB::Util::Multilingual
+ canonical:
+ :de: Durchstechflasche
+ synonyms: []
+
+ - &id003 !de.oddb.org,2007/ODDB::Drugs::Part
+ oid: 1727992
+ multi:
+ quantity:
+ size: 1
+ unit: *id001
+ packages:
+ - !de.oddb.org,2007/ODDB::Drugs::Package
+ oid: 1724271
+ codes:
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: DE
+ type: cid
+ value: "3081565"
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: DE
+ type: prescription
+ value: true
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: DE
+ type: zuzahlungsbefreit
+ value: false
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: DE
+ type: festbetragsgruppe
+ value:
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: DE
+ type: festbetragsstufe
+ value:
+ data_origins:
+ :price_exfactory: hwyss@ywesee.com
+ :code_festbetragsgruppe: zdavatz@ywesee.com
+ :code_zuzahlungsbefreit: zdavatz@ywesee.com
+ :code_festbetragsstufe: zdavatz@ywesee.com
+ :size: hwyss@ywesee.com
+ :name: zdavatz@ywesee.com
+ :price_public: zdavatz@ywesee.com
+ name: !de.oddb.org,2007/ODDB::Util::Multilingual
+ canonical:
+ :de: Argatra(R) 100 mg/ml Argatroban (N1)
+ synonyms: []
+
+ parts:
+ - *id002
+ prices:
+ public: 238.11
+ - !de.oddb.org,2007/ODDB::Drugs::Package
+ oid: 1727993
+ codes:
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: DE
+ type: prescription
+ value: true
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: DE
+ type: zuzahlungsbefreit
+ value: false
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: DE
+ type: festbetragsgruppe
+ value:
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: DE
+ type: festbetragsstufe
+ value:
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: DE
+ type: cid
+ value: "1022245"
+ data_origins:
+ :price_exfactory: hwyss@ywesee.com
+ :code_festbetragsgruppe: zdavatz@ywesee.com
+ :code_zuzahlungsbefreit: zdavatz@ywesee.com
+ :code_festbetragsstufe: zdavatz@ywesee.com
+ :size: hwyss@ywesee.com
+ :code_cid: zdavatz@ywesee.com
+ :name: zdavatz@ywesee.com
+ :price_public: hwyss@ywesee.com
+ :code_prescription: zdavatz@ywesee.com
+ name: !de.oddb.org,2007/ODDB::Util::Multilingual
+ canonical:
+ :de: Argatra(R) 100 mg/ml Argatroban (Klinikpackung)
+ synonyms: []
+
+ parts:
+ - *id003
+ prices:
+ exfactory: 158.0
+--- !de.oddb.org,2007/ODDB::Drugs::Product
+oid: 1841680
+name: !de.oddb.org,2007/ODDB::Util::Multilingual
+ canonical:
+ :de: ASTHMA BRONCHIALE STAUFEN
+ synonyms: []
+
+company: !de.oddb.org,2007/ODDB::Business::Company
+ oid: 1841686
+ name: !de.oddb.org,2007/ODDB::Util::Multilingual
+ canonical:
+ :de: Staufen Pharma
+ synonyms: []
+
+sequences:
+- !de.oddb.org,2007/ODDB::Drugs::Sequence
+ oid: 1841675
+ codes:
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: EU
+ type: registration
+ value: 2510055.00.00
+ name: !de.oddb.org,2007/ODDB::Util::Multilingual
+ canonical: {}
+
+ synonyms: []
+
+ patinfo_url: http://gripsdb.dimdi.de/amispb/doc/2009/03/07/2510055/OBFME745B5B701C954E7.rtf
+ compositions:
+ - !de.oddb.org,2007/ODDB::Drugs::Composition
+ oid: 1841672
+ galenic_form: !de.oddb.org,2007/ODDB::Drugs::GalenicForm
+ oid: 18210
+ codes:
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: DE
+ type: galenic_form
+ value: AMP
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: DE
+ type: galenic_form
+ value: AMP1
+ description: !de.oddb.org,2007/ODDB::Util::Multilingual
+ canonical:
+ :de: Ampullen
+ synonyms: []
+
+ active_agents:
+ - !de.oddb.org,2007/ODDB::Drugs::ActiveAgent
+ oid: 1841674
+ dose: !de.oddb.org,2007/ODDB::Drugs::Dose
+ val: 1
+ unit: ml
+ substance: !de.oddb.org,2007/ODDB::Drugs::Substance
+ oid: 1841670
+ name: !de.oddb.org,2007/ODDB::Util::Multilingual
+ canonical:
+ :de: Asthma-bronchiale-Nosode (Pot.-Angaben)
+ synonyms: []
+
+ parts:
+ - &id001 !de.oddb.org,2007/ODDB::Drugs::Part
+ oid: 1841683
+ multi:
+ size: 10
+ unit: !de.oddb.org,2007/ODDB::Drugs::Unit
+ oid: 19684
+ name: !de.oddb.org,2007/ODDB::Util::Multilingual
+ canonical:
+ :de: Ampullen
+ synonyms: []
+
+ packages:
+ - !de.oddb.org,2007/ODDB::Drugs::Package
+ oid: 1841684
+ codes:
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: DE
+ type: cid
+ value: "4661796"
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: DE
+ type: prescription
+ value: false
+ data_origins:
+ :price_public: :csv_product_infos
+ name: !de.oddb.org,2007/ODDB::Util::Multilingual
+ canonical:
+ :de: Asthma Bronchiale Nosoden Ser. Ampullen
+ synonyms: []
+
+ parts:
+ - *id001
+ prices:
+ public: 15.3866
+--- !de.oddb.org,2007/ODDB::Drugs::Product
+oid: 27823
+name: !de.oddb.org,2007/ODDB::Util::Multilingual
+ canonical:
+ :de: Aarane
+ synonyms: []
+
+company: !de.oddb.org,2007/ODDB::Business::Company
+ oid: 213595
+ name: !de.oddb.org,2007/ODDB::Util::Multilingual
+ canonical:
+ :de: Sanofi-Aventis Dt. GmbH
+ synonyms: []
+
+sequences:
+- !de.oddb.org,2007/ODDB::Drugs::Sequence
+ oid: 27830
+ codes:
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: EU
+ type: registration
+ value: 3159.00.00
+ fachinfo_url: http://gripsdb.dimdi.de/amispb/doc/2009/02/27/2103159/OBFMDE81481A01C93A3F.rtf
+ name: !de.oddb.org,2007/ODDB::Util::Multilingual
+ canonical: {}
+
+ synonyms: []
+
+ patinfo_url: http://gripsdb.dimdi.de/amispb/doc/2009/02/27/2103159/OBFMDEDBE17601C93A3F.rtf
+ atc: !de.oddb.org,2007/ODDB::Drugs::Atc
+ oid: 13239
+ code: R03AK05
+ ddd_guidelines: !de.oddb.org,2007/ODDB::Util::Multilingual
+ canonical: {}
+
+ synonyms: []
+
+ guidelines: !de.oddb.org,2007/ODDB::Util::Multilingual
+ canonical: {}
+
+ synonyms: []
+
+ name: !de.oddb.org,2007/ODDB::Util::Multilingual
+ canonical:
+ :en: Reproterol and Other Drugs for Obstructive Airway Diseases
+ :de: "Reproterol und andere Mittel bei obstruktiven Atemwegserkrankungen "
+ synonyms: []
+
+ ddds: []
+
+ compositions:
+ - !de.oddb.org,2007/ODDB::Drugs::Composition
+ oid: 27825
+ equivalence_factor: 0.25
+ galenic_form: !de.oddb.org,2007/ODDB::Drugs::GalenicForm
+ oid: 18225
+ codes:
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: DE
+ type: galenic_form
+ value: DA
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: DE
+ type: galenic_form
+ value: DA1
+ description: !de.oddb.org,2007/ODDB::Util::Multilingual
+ canonical:
+ :de: Dosieraerosol
+ synonyms: []
+
+ active_agents:
+ - !de.oddb.org,2007/ODDB::Drugs::ActiveAgent
+ oid: 27827
+ dose: !de.oddb.org,2007/ODDB::Drugs::Dose
+ val: 0.5
+ unit: mg
+ substance: !de.oddb.org,2007/ODDB::Drugs::Substance
+ oid: 258913
+ codes: []
+
+ name: !de.oddb.org,2007/ODDB::Util::Multilingual
+ canonical:
+ :de: Reproterolhydrochlorid
+ synonyms: []
+
+ - !de.oddb.org,2007/ODDB::Drugs::ActiveAgent
+ oid: 27828
+ dose: !de.oddb.org,2007/ODDB::Drugs::Dose
+ val: 1
+ unit: mg
+ substance: !de.oddb.org,2007/ODDB::Drugs::Substance
+ oid: 258916
+ codes: []
+
+ name: !de.oddb.org,2007/ODDB::Util::Multilingual
+ canonical:
+ :de: Natriumcromoglicat (Ph.Eur.)
+ synonyms: []
+
+ parts:
+ - &id001 !de.oddb.org,2007/ODDB::Drugs::Part
+ oid: 27834
+ multi:
+ quantity: !de.oddb.org,2007/ODDB::Drugs::Dose
+ val: 10
+ unit: ml
+ size: 1
+ unit: &id002 !de.oddb.org,2007/ODDB::Drugs::Unit
+ oid: 27833
+ name: !de.oddb.org,2007/ODDB::Util::Multilingual
+ canonical:
+ :de: Dosieraerosol
+ synonyms: []
+
+ packages:
+ - !de.oddb.org,2007/ODDB::Drugs::Package
+ oid: 27835
+ codes:
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: DE
+ type: cid
+ value: "225437"
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: DE
+ type: festbetragsgruppe
+ value: "1"
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: DE
+ type: festbetragsstufe
+ value: 3
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: DE
+ type: prescription
+ value: true
+ data_origins:
+ :price_exfactory: :dimdi
+ :price_public: :dimdi
+ :price_festbetrag: :dimdi
+ name: !de.oddb.org,2007/ODDB::Util::Multilingual
+ canonical:
+ :de: Aarane N Dos.-Aerosol
+ synonyms: []
+
+ parts:
+ - *id001
+ prices:
+ festbetrag: 41.63
+ exfactory: 27.483606557377
+ public: 41.63
+ - !de.oddb.org,2007/ODDB::Drugs::Package
+ oid: 27846
+ codes:
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: DE
+ type: cid
+ value: "225443"
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: DE
+ type: festbetragsgruppe
+ value: "1"
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: DE
+ type: festbetragsstufe
+ value: 3
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: DE
+ type: prescription
+ value: true
+ data_origins:
+ :price_exfactory: :dimdi
+ :price_public: :dimdi
+ :price_festbetrag: :dimdi
+ name: !de.oddb.org,2007/ODDB::Util::Multilingual
+ canonical:
+ :de: Aarane N Dos.-Aerosol
+ synonyms: []
+
+ parts:
+ - !de.oddb.org,2007/ODDB::Drugs::Part
+ oid: 27845
+ multi:
+ quantity: !de.oddb.org,2007/ODDB::Drugs::Dose
+ val: 10
+ unit: ml
+ size: 2
+ unit: *id002
+ prices:
+ festbetrag: 70.44
+ exfactory: 51.0983606557377
+ public: 70.44
+ - !de.oddb.org,2007/ODDB::Drugs::Package
+ oid: 27857
+ codes:
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: DE
+ type: cid
+ value: "225466"
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: DE
+ type: festbetragsgruppe
+ value: "1"
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: DE
+ type: festbetragsstufe
+ value: 3
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: DE
+ type: prescription
+ value: true
+ data_origins:
+ :price_exfactory: :dimdi
+ :price_public: :dimdi
+ :price_festbetrag: :dimdi
+ name: !de.oddb.org,2007/ODDB::Util::Multilingual
+ canonical:
+ :de: Aarane N Dos.-Aerosol
+ synonyms: []
+
+ parts:
+ - !de.oddb.org,2007/ODDB::Drugs::Part
+ oid: 27856
+ multi:
+ quantity: !de.oddb.org,2007/ODDB::Drugs::Dose
+ val: 10
+ unit: ml
+ size: 3
+ unit: *id002
+ prices:
+ festbetrag: 98.14
+ exfactory: 73.8032786885246
+ public: 98.14
+--- !de.oddb.org,2007/ODDB::Drugs::Product
+oid: 123058
+name: !de.oddb.org,2007/ODDB::Util::Multilingual
+ canonical:
+ :de: Ass Stada
+ synonyms: []
+
+company: !de.oddb.org,2007/ODDB::Business::Company
+ oid: 213544
+ name: !de.oddb.org,2007/ODDB::Util::Multilingual
+ canonical:
+ :de: Stadapharm GmbH
+ synonyms: []
+
+sequences:
+- !de.oddb.org,2007/ODDB::Drugs::Sequence
+ oid: 123064
+ atc: !de.oddb.org,2007/ODDB::Drugs::Atc
+ oid: 10794
+ code: N02BA01
+ name: !de.oddb.org,2007/ODDB::Util::Multilingual
+ canonical:
+ :en: Acetylsalicylic Acid
+ :de: "Acetylsalicyls\xC3\xA4ure"
+ synonyms: []
+
+ ddds:
+ - !de.oddb.org,2007/ODDB::Drugs::Ddd
+ oid: 17503
+ administration: O
+ comment:
+ dose: !de.oddb.org,2007/ODDB::Drugs::Dose
+ val: 3
+ unit: g
+ - !de.oddb.org,2007/ODDB::Drugs::Ddd
+ oid: 17504
+ administration: P
+ comment: bezogen auf Lysinacetylsalicylat
+ dose: !de.oddb.org,2007/ODDB::Drugs::Dose
+ val: 1
+ unit: g
+ - !de.oddb.org,2007/ODDB::Drugs::Ddd
+ oid: 17505
+ administration: R
+ comment:
+ dose: !de.oddb.org,2007/ODDB::Drugs::Dose
+ val: 3
+ unit: g
+ compositions:
+ - !de.oddb.org,2007/ODDB::Drugs::Composition
+ oid: 123060
+ equivalence_factor: 500.0
+ galenic_form: &id004 !de.oddb.org,2007/ODDB::Drugs::GalenicForm
+ oid: 18322
+ codes:
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: DE
+ type: galenic_form
+ value: TAB1
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: DE
+ type: galenic_form
+ value: TABL
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: DE
+ type: galenic_form
+ value: TABL1
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: DE
+ type: galenic_form
+ value: TABL2
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: DE
+ type: galenic_form
+ value: TABL3
+ description: !de.oddb.org,2007/ODDB::Util::Multilingual
+ canonical:
+ :de: Tabletten
+ synonyms:
+ - Tablette
+ group: !de.oddb.org,2007/ODDB::Drugs::GalenicGroup
+ oid: 18348
+ administration: O
+ name: !de.oddb.org,2007/ODDB::Util::Multilingual
+ canonical:
+ :de: Tabletten
+ synonyms: []
+
+ active_agents:
+ - !de.oddb.org,2007/ODDB::Drugs::ActiveAgent
+ oid: 123062
+ dose: !de.oddb.org,2007/ODDB::Drugs::Dose
+ val: 500
+ unit: mg
+ substance: &id005 !de.oddb.org,2007/ODDB::Drugs::Substance
+ oid: 18991
+ codes: []
+
+ name: !de.oddb.org,2007/ODDB::Util::Multilingual
+ canonical:
+ :de: "Acetylsalicyls\xC3\xA4ure"
+ synonyms:
+ - ASS
+ group: !de.oddb.org,2007/ODDB::Drugs::SubstanceGroup
+ oid: 18993
+ name: !de.oddb.org,2007/ODDB::Util::Multilingual
+ canonical:
+ :de: ASS / ASS-Puffer
+ synonyms: []
+
+ parts:
+ - &id002 !de.oddb.org,2007/ODDB::Drugs::Part
+ oid: 123067
+ multi:
+ size: 10
+ unit: &id001 !de.oddb.org,2007/ODDB::Drugs::Unit
+ oid: 18979
+ name: !de.oddb.org,2007/ODDB::Util::Multilingual
+ canonical:
+ :de: Tabletten
+ synonyms: []
+
+ - &id003 !de.oddb.org,2007/ODDB::Drugs::Part
+ oid: 166317
+ multi:
+ size: 30
+ unit: *id001
+ packages:
+ - !de.oddb.org,2007/ODDB::Drugs::Package
+ oid: 123068
+ codes:
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: DE
+ type: cid
+ value: "3366167"
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: DE
+ type: festbetragsgruppe
+ value: "1"
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: DE
+ type: festbetragsstufe
+ value: 3
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: DE
+ type: prescription
+ value: false
+ data_origins:
+ :price_public: :dimdi
+ :price_festbetrag: :dimdi
+ name: !de.oddb.org,2007/ODDB::Util::Multilingual
+ canonical:
+ :de: Ass Stada 500 Tabletten
+ synonyms: []
+
+ parts:
+ - *id002
+ prices:
+ festbetrag: 1.62
+ public: 1.34
+ - !de.oddb.org,2007/ODDB::Drugs::Package
+ oid: 166318
+ codes:
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: DE
+ type: cid
+ value: "4860432"
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: DE
+ type: festbetragsgruppe
+ value: "1"
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: DE
+ type: festbetragsstufe
+ value: 3
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: DE
+ type: prescription
+ value: false
+ data_origins:
+ :price_public: :dimdi
+ :price_festbetrag: :dimdi
+ name: !de.oddb.org,2007/ODDB::Util::Multilingual
+ canonical:
+ :de: Ass Stada 500 Tabletten
+ synonyms: []
+
+ parts:
+ - *id003
+ prices:
+ festbetrag: 3.45
+ public: 1.59
+- !de.oddb.org,2007/ODDB::Drugs::Sequence
+ oid: 187618
+ codes: []
+
+ fachinfo_url: http://gripsdb.dimdi.de/amispb/doc/2007/10/20/2149897/OBFME354082201C79E74.rtf
+ name: !de.oddb.org,2007/ODDB::Util::Multilingual
+ canonical: {}
+
+ synonyms: []
+
+ patinfo_url: http://gripsdb.dimdi.de/amispb/doc/2007/10/20/2149897/OBFME3351D5E01C79E74.rtf
+ atc: !de.oddb.org,2007/ODDB::Drugs::Atc
+ oid: 2160
+ code: B01AC06
+ name: !de.oddb.org,2007/ODDB::Util::Multilingual
+ canonical:
+ :en: Acetylsalicylic Acid
+ :de: "Acetylsalicyls\xC3\xA4ure"
+ synonyms: []
+
+ ddds:
+ - !de.oddb.org,2007/ODDB::Drugs::Ddd
+ oid: 16383
+ administration: O
+ comment: "unabh\xC3\xA4ngig von der Wirkst\xC3\xA4rke"
+ dose: !de.oddb.org,2007/ODDB::Drugs::Dose
+ val: 1
+ unit: ""
+ compositions:
+ - !de.oddb.org,2007/ODDB::Drugs::Composition
+ oid: 187614
+ equivalence_factor: 100.0
+ galenic_form: *id004
+ active_agents:
+ - !de.oddb.org,2007/ODDB::Drugs::ActiveAgent
+ oid: 187616
+ dose: !de.oddb.org,2007/ODDB::Drugs::Dose
+ val: 100
+ unit: mg
+ substance: *id005
+ parts:
+ - &id006 !de.oddb.org,2007/ODDB::Drugs::Part
+ oid: 187621
+ multi:
+ size: 50
+ unit: *id001
+ - &id007 !de.oddb.org,2007/ODDB::Drugs::Part
+ oid: 187624
+ multi:
+ size: 100
+ unit: *id001
+ - &id008 !de.oddb.org,2007/ODDB::Drugs::Part
+ oid: 188222
+ multi:
+ size: 20
+ unit: *id001
+ packages:
+ - !de.oddb.org,2007/ODDB::Drugs::Package
+ oid: 187622
+ codes:
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: DE
+ type: cid
+ value: "7382275"
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: DE
+ type: festbetragsgruppe
+ value: "1"
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: DE
+ type: festbetragsstufe
+ value: 3
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: DE
+ type: prescription
+ value: false
+ data_origins:
+ :price_public: :dimdi
+ :price_festbetrag: :dimdi
+ name: !de.oddb.org,2007/ODDB::Util::Multilingual
+ canonical:
+ :de: Ass Stada 100 Tabletten
+ synonyms: []
+
+ parts:
+ - *id006
+ prices:
+ festbetrag: 2.64
+ public: 1.64
+ - !de.oddb.org,2007/ODDB::Drugs::Package
+ oid: 187625
+ codes:
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: DE
+ type: cid
+ value: "7382281"
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: DE
+ type: festbetragsgruppe
+ value: "1"
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: DE
+ type: festbetragsstufe
+ value: 3
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: DE
+ type: prescription
+ value: false
+ data_origins:
+ :price_public: :dimdi
+ :price_festbetrag: :dimdi
+ name: !de.oddb.org,2007/ODDB::Util::Multilingual
+ canonical:
+ :de: Ass Stada 100 Tabletten
+ synonyms: []
+
+ parts:
+ - *id007
+ prices:
+ festbetrag: 4.26
+ public: 2.87
+ - !de.oddb.org,2007/ODDB::Drugs::Package
+ oid: 188223
+ codes:
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: DE
+ type: cid
+ value: "7394433"
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: DE
+ type: festbetragsgruppe
+ value: "1"
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: DE
+ type: festbetragsstufe
+ value: 3
+ - !de.oddb.org,2007/ODDB::Util::Code
+ country: DE
+ type: prescription
+ value: false
+ data_origins:
+ :price_public: :dimdi
+ :price_festbetrag: :dimdi
+ name: !de.oddb.org,2007/ODDB::Util::Multilingual
+ canonical:
+ :de: Ass Stada 100 Tabletten
+ synonyms: []
+
+ parts:
+ - *id008
+ prices:
+ festbetrag: 1.42
+ public: 1.14
diff --git a/src/test/resources/issues/issue59-1.yaml b/src/test/resources/issues/issue59-1.yaml
new file mode 100644
index 0000000..dac8f8b
--- /dev/null
+++ b/src/test/resources/issues/issue59-1.yaml
@@ -0,0 +1,8 @@
+!!org.yaml.snakeyaml.issues.issue60.SkipBean
+text: foo
+number: null
+map: {}
+listStr: [bar, null, foo, null]
+listInt: [null, 1, 2, 3]
+listDate: null
+empty: []
\ No newline at end of file
diff --git a/src/test/resources/issues/issue59-2.yaml b/src/test/resources/issues/issue59-2.yaml
new file mode 100644
index 0000000..801d910
--- /dev/null
+++ b/src/test/resources/issues/issue59-2.yaml
@@ -0,0 +1,7 @@
+!!org.yaml.snakeyaml.issues.issue60.SkipBean
+listStr: [bar, null, foo, null]
+listDate: null
+empty: []
+map: {}
+text: foo
+number: null
\ No newline at end of file
diff --git a/src/test/resources/issues/issue60-1.yaml b/src/test/resources/issues/issue60-1.yaml
new file mode 100644
index 0000000..0d148e8
--- /dev/null
+++ b/src/test/resources/issues/issue60-1.yaml
@@ -0,0 +1,6 @@
+!!org.yaml.snakeyaml.issues.issue60.SkipBean
+empty: []
+listInt: [null, 1, 2, 3]
+listStr: [bar, null, foo, null]
+map: {}
+text: foo
diff --git a/src/test/resources/issues/issue60-2.yaml b/src/test/resources/issues/issue60-2.yaml
new file mode 100644
index 0000000..d5100c3
--- /dev/null
+++ b/src/test/resources/issues/issue60-2.yaml
@@ -0,0 +1,4 @@
+!!org.yaml.snakeyaml.issues.issue60.SkipBean
+listInt: [null, 1, 2, 3]
+listStr: [bar, null, foo, null]
+text: foo
diff --git a/src/test/resources/issues/issue61-1.yaml b/src/test/resources/issues/issue61-1.yaml
new file mode 100644
index 0000000..80361f2
--- /dev/null
+++ b/src/test/resources/issues/issue61-1.yaml
@@ -0,0 +1,7 @@
+list:
+- !!org.yaml.snakeyaml.issues.issue61.GenericListBeanTest$Bean
+ name: foo
+ number: 0
+- !!org.yaml.snakeyaml.issues.issue61.GenericListBeanTest$Bean
+ name: bar
+ number: 3
diff --git a/src/test/resources/issues/issue61-2.yaml b/src/test/resources/issues/issue61-2.yaml
new file mode 100644
index 0000000..2aea65c
--- /dev/null
+++ b/src/test/resources/issues/issue61-2.yaml
@@ -0,0 +1,7 @@
+map:
+ foo: !!org.yaml.snakeyaml.issues.issue61.GenericMapBeanTest$Bean
+ name: foo
+ number: 0
+ bar: !!org.yaml.snakeyaml.issues.issue61.GenericMapBeanTest$Bean
+ name: bar
+ number: 3
diff --git a/src/test/resources/issues/issue67-error1.txt b/src/test/resources/issues/issue67-error1.txt
new file mode 100644
index 0000000..a171ab1
--- /dev/null
+++ b/src/test/resources/issues/issue67-error1.txt
@@ -0,0 +1,8 @@
+while scanning a tag
+ in 'string', line 1, column 1:
+ !!org.yaml.snakeyaml.issues.issu ...
+ ^
+expected URI escape sequence of 2 hexadecimal numbers, but found 9(57) and %(37)
+ in 'string', line 1, column 71:
+ ... nAsciiCharsInClassNameTest$Acad%9%A9mico {id: 3, name: Foo bar}
+ ^
diff --git a/src/test/resources/issues/issue67-error2.txt b/src/test/resources/issues/issue67-error2.txt
new file mode 100644
index 0000000..8673ae0
--- /dev/null
+++ b/src/test/resources/issues/issue67-error2.txt
@@ -0,0 +1,8 @@
+while scanning a tag
+ in 'string', line 1, column 1:
+ !!org.yaml.snakeyaml.issues.issu ...
+ ^
+expected URI in UTF-8: Input length = 1
+ in 'string', line 1, column 70:
+ ... onAsciiCharsInClassNameTest$Acad%C0mico {id: 3, name: Foo bar}
+ ^
diff --git a/src/test/resources/issues/issue68.txt b/src/test/resources/issues/issue68.txt
new file mode 100644
index 0000000..cd4230b
--- /dev/null
+++ b/src/test/resources/issues/issue68.txt
@@ -0,0 +1,2 @@
+И жить торопится и чувствовать спешит...
+
diff --git a/src/test/resources/issues/issue73-1.txt b/src/test/resources/issues/issue73-1.txt
new file mode 100644
index 0000000..78f262a
--- /dev/null
+++ b/src/test/resources/issues/issue73-1.txt
@@ -0,0 +1,10 @@
+!!org.yaml.snakeyaml.issues.issue73.Blog
+labels: !!set {Java: null, SnakeYAML: null, YAML: null}
+name: Test Me!
+numbers: !!set {19: null, 17: null}
+posts: !!set
+ ? {text: text 1, title: Title1}
+ : null
+ ? {text: text text 2, title: Title2}
+ : null
+
diff --git a/src/test/resources/issues/issue73-2.txt b/src/test/resources/issues/issue73-2.txt
new file mode 100644
index 0000000..ade8322
--- /dev/null
+++ b/src/test/resources/issues/issue73-2.txt
@@ -0,0 +1,7 @@
+name: No tags!
+posts:
+ - text: Dummy
+ title: Test
+ - text: Creative
+ title: Highly
+
diff --git a/src/test/resources/issues/issue73-3.txt b/src/test/resources/issues/issue73-3.txt
new file mode 100644
index 0000000..c188fe0
--- /dev/null
+++ b/src/test/resources/issues/issue73-3.txt
@@ -0,0 +1,5 @@
+!!java.util.HashSet
+- aaa
+- bbb
+- ccc
+
diff --git a/src/test/resources/issues/issue73-6.txt b/src/test/resources/issues/issue73-6.txt
new file mode 100644
index 0000000..57d49dc
--- /dev/null
+++ b/src/test/resources/issues/issue73-6.txt
@@ -0,0 +1,5 @@
+!!java.util.TreeSet
+- aaa
+- bbb
+- ccc
+
diff --git a/src/test/resources/issues/issue73-dump7.txt b/src/test/resources/issues/issue73-dump7.txt
new file mode 100644
index 0000000..0d36c28
--- /dev/null
+++ b/src/test/resources/issues/issue73-dump7.txt
@@ -0,0 +1,8 @@
+!!org.yaml.snakeyaml.issues.issue73.Blog
+labels: [Java, SnakeYAML, YAML]
+name: Test Me!
+numbers: [19, 17]
+posts:
+- {text: text 1, title: Title1}
+- {text: text text 2, title: Title2}
+
diff --git a/src/test/resources/issues/issue73-dump8.txt b/src/test/resources/issues/issue73-dump8.txt
new file mode 100644
index 0000000..2b61b71
--- /dev/null
+++ b/src/test/resources/issues/issue73-dump8.txt
@@ -0,0 +1,15 @@
+!!org.yaml.snakeyaml.issues.issue73.Blog
+labels:
+- Java
+- SnakeYAML
+- YAML
+name: Test Me!
+numbers:
+- 19
+- 17
+posts:
+- text: text 1
+ title: Title1
+- text: text text 2
+ title: Title2
+
diff --git a/src/test/resources/issues/issue73-recursive10.txt b/src/test/resources/issues/issue73-recursive10.txt
new file mode 100644
index 0000000..772fe92
--- /dev/null
+++ b/src/test/resources/issues/issue73-recursive10.txt
@@ -0,0 +1,5 @@
+&id001 !!java.util.TreeSet
+- aaa
+- !!set { 1, *id001 }
+- ccc
+
diff --git a/src/test/resources/issues/issue73-recursive4.txt b/src/test/resources/issues/issue73-recursive4.txt
new file mode 100644
index 0000000..5141208
--- /dev/null
+++ b/src/test/resources/issues/issue73-recursive4.txt
@@ -0,0 +1,5 @@
+&id001 !!java.util.HashSet
+- aaa
+- !!set { 1, *id001 }
+- ccc
+
diff --git a/src/test/resources/issues/issue73-recursive5.txt b/src/test/resources/issues/issue73-recursive5.txt
new file mode 100644
index 0000000..ddb7c42
--- /dev/null
+++ b/src/test/resources/issues/issue73-recursive5.txt
@@ -0,0 +1,4 @@
+!!org.yaml.snakeyaml.issues.issue73.RecursiveSetTest$Bean1
+id: ID123
+set: &id001 !!set {ccc: null, *id001: null, zzz: null}
+
diff --git a/src/test/resources/issues/issue73-recursive9.txt b/src/test/resources/issues/issue73-recursive9.txt
new file mode 100644
index 0000000..35620c7
--- /dev/null
+++ b/src/test/resources/issues/issue73-recursive9.txt
@@ -0,0 +1,7 @@
+&id001 !!org.yaml.snakeyaml.issues.issue73.RecursiveSortedSetTest$Bean11
+id: ID555
+set: !!set
+ *id001: null
+ ggg: null
+ hhh: null
+
diff --git a/src/test/resources/issues/issue74-array1.txt b/src/test/resources/issues/issue74-array1.txt
new file mode 100644
index 0000000..45c05d8
--- /dev/null
+++ b/src/test/resources/issues/issue74-array1.txt
@@ -0,0 +1,20 @@
+id: ID123
+list:
+- age: 111
+ name: John
+- age: 222
+ name: Tony
+members:
+- age: 21
+ name: Foo
+- age: 23
+ name: Bar
+- age: 25
+ name: Hue Long Hair
+number: 7
+openMembers:
+- age: 1000
+ name: OpenFoo
+- age: 2000
+ name: OpenBar
+
diff --git a/src/test/resources/issues/issue99-base64_double_quoted.yaml b/src/test/resources/issues/issue99-base64_double_quoted.yaml
new file mode 100644
index 0000000..8c1fccc
--- /dev/null
+++ b/src/test/resources/issues/issue99-base64_double_quoted.yaml
@@ -0,0 +1,82 @@
+jpegPhoto: !!binary
+ "/9j/4AAQSkZJRgABAQEASABIAAD/2wBDAAUDBAQEAwUEBAQFBQUGBwwIBwcHBw8L\
+ CwkMEQ8SEhEPERETFhwXExQaFRERGCEYGh0dHx8fExciJCIeJBweHx7/2wBDAQUF\
+ BQcGBw4ICA4eFBEUHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4e\
+ Hh4eHh4eHh4eHh4eHh7/wAARCAB4AFoDASIAAhEBAxEB/8QAHAAAAgMBAQEBAAAA\
+ AAAAAAAABgcEBQgAAgMB/8QAORAAAQMDAwEGAwYEBwEAAAAAAQIDBAAFEQYSITET\
+ IkFRYXEHMpEUFYGhwfAII7HRM0JSYoKywuH/xAAaAQACAwEBAAAAAAAAAAAAAAAE\
+ BQEDBgAC/8QAIhEAAgICAgIDAQEAAAAAAAAAAQIAAwQREiETMQUiQVEy/9oADAMB\
+ AAIRAxEAPwDOejbio3MgNkoBzx403LRcba9taeHzdQpGaUuhbbJBLqmyCTwFGtAa\
+ VssPR+nEauu7bUi6vNlVuhKGQhPQOrHrzgeuaUlx5CB+Q6xAToSzl6G0sbSX7kwL\
+ eopSrOdiiD44496A9Tat0fopxVr0xp9i5P7QXJUokkkjkDk4HT69KqNYXW+6mbU8\
+ 7NdSEkFSArr1Ph654obVY1d3ajKyOQR1J65rnyFHqGY3x4H+zL25a8WbQVW6JDjP\
+ ye6pDaMBOTnA5JxQpMuFyW+p1bq2Gkj+YtTg7VZxnAPhk+H9jV/H0bOdHaMMrCuq\
+ ldMDpxnx9arJNlVFugQ5hQSNzfJwXMDk+mfChxcpMZeAKvQg6JNzRh37xeZQQT3X\
+ VZx7Cor2oXA2WnFrlbvmLv79vwqxv6mXZS27eypcfHZoUB3lkY6DwAHHl60Jzmih\
+ agpO1aSQpOOhzRtaBvcFtOl3qXcGTAccy1hBI7zav05HSruySnWpaXgXMAju8cUu\
+ iopOc0XaUk/a2XEqGX2xnOfmT5+4/tU20lRyEUOQzR32S5R3ogSp7flPAzU8qJOQ\
+ gkH/AGml7pBa2UDKio5yAPD3o1DM5Q3BSMHn5agN1KCmjPvZbBD7dDLSSgpO4YTk\
+ evtV/qeDKuMtx95bi0tNgNZHAx0FRPhszMvsh+DGBb+0OIaLikghIGSceXFNu82O\
+ ElhiDDbCGY7ewqV1V6nHiTk/jSkbVN/2NMZCXiSa0+slwJTkqGMefBP61e6f0ehJ\
+ S9JRvIGcEdPWmPBs8VkjDaVFI4PlUlcZs90J6jp4Cg2tYjUd1167MEJFvbDHYttb\
+ ePLGfegjUejWJOOFpWAccc+PNN+ZGQ03whO7zBoWvZUkJSAULzjjy8qo2yncLBB6\
+ Ez9PtAgF+M0hxK14ClJQTsTjqD5nz/pQPfrQzDkFKHVBBBJC8bv3mnjqWKFdqAUg\
+ gZ56e9JrV6GG5C1POpMjdykf1JH9Kd4drNqK7l+x3A+Q1jywK/LZNXBmIebJ7p5G\
+ cbh4ivcxRWsgDBPgKgrSUmnSDY0YiydK+1EdXw5kxJRD8lYCAchGfA9KbKLlaQgA\
+ IGAOM1nbQLjaoY3Faih3apKVYwPP14zTJaS4W0kB7GBj+ef7UEx8balDKD3HL/D3\
+ GS3bn5rqBvUVBvHJwTg/9aYU11CXVjvKz1pZfAi8PTtBwpLiW2nj3XCgYTkFQyB+\
+ +tMGSHStKgQkEdSOT60lym4nj/JpcKromcHh2OEkJHOec1+sqZQ0FFaNxHOSMV8U\
+ Mt56Eq8Sal9kSlISkEEZJ/YoVezuHtoCRnlMvIwFNrUPLAPvmhTUTZ+0jI7oPBJ5\
+ omngJwFKaRn/AFdKF7q4ytpSkuIVuB2hKs8+H1ry7danVqd7EXOqloZD6lJWcHOS\
+ OlIvV+H7o4GknJV08Qa0VLtbd0SsrAwrPgMUr9caNQzMBbUEhwAjwz9KMwchVbRl\
+ V1QOyYo3I6kK5UCRzwc4qysdhTOQp+XJ+zM52IIb3rWrwATkZNXuorGm2x9iSlKX\
+ FY2j51gfpk5/D0o6+FFmjSbM/LeLSZCDhhChy2Bz18zjk9ab3ZfCvkIFRhpbZ9h1\
+ ATQdrl2/V0i2yUqSSxvA5AXyNpH4E05G4b/Zp/lNdB1UaiTYraHbVdOxSXWn3Iq+\
+ OQhbZUOfRTYx71cC4pAA7PpQ75At00V5uMcezgIM/wAKNznLVcrWgl1hlxD2wnhI\
+ VkEj6CtGOPI2FeRvA5yoHB/SsY/Ci4XCFeXodskiM+8nBcz/AKT+fU00b5JesUJt\
+ 67a67F50ghlKdzh/4p5x6kUHn18rjr2ZocRNVgx4SLuw2ELUDtVwQmgHXPxTmRZS\
+ bTp2KX5KuFLKeB6elSPhNLF/t8pDr7jwawQ6pop3pUOD3qB73pq9RLtOfgSUpS+8\
+ U9qcbmkjB/DrQCNxPcOCI5hLAsWp75GTPv8AeVoUeUx2lAbfc14RBnWx4NtrW+0V\
+ JThQ564HNRYOioc2JHkXPUV0CGUntUInrSHT1BOensKurTp23x3g7EmSRDz3W3Hl\
+ upV5Eknj61FjLr3uQFPoCWCGUNs5ABThXeHy+2fqKDtdsibEU9HCSWu6lR88UY3t\
+ SlNIyph1lPADeUhIHljIxQhqF5pFvdhKSEoIIUQfDNVI33Ek17WKCY46/duycaDr\
+ +3B7QlIPoCDnzoq0tpftUCYiUuLNTne2FHa4Bz+BxQxGbdYuDqHR2oB7iuufbyNO\
+ TSEq3tbH5bjPauISlEdPJ3HxIHkP60zvtIUASjHXgSRPEtovpag7FhbbTXaE9Svv\
+ YPvtNQlWe4BRwhRGevNGGm2I8y+zIuMuspD7pzk5cPGfLhJou+7GPFsfSrcfHLJu\
+ IPlsjnf6mIbBMkRtQx5UUBLq1bBnnG4bc/nWiNKWHTtu7EKtjF2uyk5dkPntClRH\
+ PB6e1ZrYc7C4NSWwQhKwoAnJGK2LpK5xpFihutoawGxjAx4dan5Z2TiVjr45OYYG\
+ XOm2Psbco9m0krKVKCEbUjjpXiNHSt5TymEOJUTlJOOK+1snQ126S4Xkghas56k+\
+ FUDuorPa2Frn3JllalHAWsAkenNJu3PQjBV4jUuHbDbhJEhERtSTzjAOPbFXEWJH\
+ jRApDaW0qHQcflS+td3cvSpMqFIcZZZIDLqU8OnxGPEeteXdVSGEGLcApp0HCVf5\
+ T/8Aa4gjsz0F5dblreWWC8p6LhtfRSAeF/h4H1oG1SwsnKkqS2fLwHlxX0vV5kMP\
+ NywT2e7vc8YzUi6b5EMrUFbSnckmq1GjuS68RqDDVigqIkckgYwOAfKpdx1rZ9Os\
+ ogMW9Kp5QNywkZBPr7VGbkFpC21KIGeKhXC222fIEqRHCnU4wsnr70ZXon7+oON+\
+ hCX+G569T9aatulxKthaa3Ag7clSijH/ABBptOXRsOKG4Dk0F/CR8N/ekZlKd7yE\
+ qzgA93j9T9RUx+NOLyzv6qP9adh+agrMdmqRcwaY5akKQShaMjyNOr4c60UqwtxH\
+ FbHW8NoOeFHGBSgblw2U4lRO0X5hWKsLFfGhPaioSGIy1gHnkHPzZ9KtzMfz1616\
+ jvCyVx7NM+9x4O3G5R0rcgK3E/4iF8gnzFVGl9PKuN/cn3mEHVuHckEFSUfXgVeJ\
+ t70a3mZGc+1d0KKFHOR5g1Y2y7T5K0x0tKjjgKW2wSduPA4xWfqYpvUeOC43CR2X\
+ CtUMJPZspSngEgYHtQcdQ2y8Xb7qQESFLJHAyPrRZD0TAl4k3NbriykqDb6uSkjg\
+ kDgH0zVvZ9P2S12tcaDFaQgnKlBI3LI8SfHwrn0R9pUNJ6gTfbPHYtLUVre4vn5j\
+ nAFTdUkwrQ2RwktJPPtX5qCUlpDzqe8oJLaeeCScAY86HfiXdFJhtRSvKkoSnr5A\
+ D9KHC7InssSIMuzAtXBGSrJBqwilSmQfDJJHp0H79aHGipw4HPPvRRAYUpKW0pyT\
+ gY9AKIPQkIO9wm+GclMbVcZJJBfy0fYjkfUCm+YbBJPZdaWvwmsTk3UL9zcwI9vQ\
+ VZI6uLylA/7H8KcyILxQk7QOOmOlOcNSU7mR+WI8/Uwx8ZdLMWK+BUNKxHfTuAPO\
+ 00AllbRCgPDNPH4l3W1XwIhY3Ps7hhIyc4pbW62pVe2oziQ4gOALB6bfGr8TKPi0\
+ 35GOR8d5bOQ9xn/CDUwutl+7pCsvso7I5PJHgf0o/gz3o7PYNR0qUk4wpWAPwpMa\
+ E09dbbeZM1lvsmQBsUrorkHH0NO2KuPJQysNDK0JJOKSZ6KlpZPRjb469mXxuexL\
+ SI9c5ZKFrHHzJSan3GW5AgBIRlWD+NfkOZFhRsBaUYzuAFCWvNWsx4J747ZY2tpB\
+ 5PhQgBb1L2JJlVcZ6VT2kLWClLpeXgcd3JA+uKX+rbsJ0tZbO1O7ABr1e7+hlvCD\
+ l9acY9+tCfaOvvbACTnJI8KNx8c/6Mgn8hRaFg9nydw8qYek7e8/hTbKluvENspA\
+ yVE9cevhQjoqyuyloG0kqIzWpfhpo0aehNXScwPvBxOIjBH+EnHznyUR9M1y0m2z\
+ QlGXlpiVEn3LDSGmm7DZotrISp7f9omLA4U4fDPknoKvl3iE2so2JO04znrVVrK7\
+ M6esrst9fexwCeVLI4T+vsDWepeo5bsp51c1e5a1KOFEck042EAAmR4tcxdoDT9N\
+ uQNU9u6G3ITru7vcFeTkoPqelMvUGh7XcRFuNpiR7c+SOwgowoDJ/wAxGennXV1L\
+ FYvoGae4lBzHufKJFbs6X4F1R2Uhg94Hz/UetC07Vka2y1IYUFN5yAMHbXV1e7aV\
+ PUS03utnMHuUd8104+sGOgFWOQRwaDrk5dZkv7XJUvcr5OMAetdXV1aLUPqI/S5n\
+ 1uQnyWhgAuPKOM0UaJ07Ouk5mHEjOSZTygAhCdxz7V1dVlnagf2erWKIWE1v8K/h\
+ zE0lEbmXJKJV0PKW08tsn/0r8hTHQ0UhyVIVlRHU/vpXV1FV1qi9TI3XPdYS5meP\
+ jBqNy+3ZxiOrdFjlSW8cbz4q/L8vWl0GMjJb6/7q6uqsnZhVY0Op/9k="
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/issues/issue99-base64_literal.yaml b/src/test/resources/issues/issue99-base64_literal.yaml
new file mode 100644
index 0000000..d6f1c6a
--- /dev/null
+++ b/src/test/resources/issues/issue99-base64_literal.yaml
@@ -0,0 +1,82 @@
+jpegPhoto: !!binary |
+ /9j/4AAQSkZJRgABAQEASABIAAD/2wBDAAUDBAQEAwUEBAQFBQUGBwwIBwcHBw8L
+ CwkMEQ8SEhEPERETFhwXExQaFRERGCEYGh0dHx8fExciJCIeJBweHx7/2wBDAQUF
+ BQcGBw4ICA4eFBEUHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4e
+ Hh4eHh4eHh4eHh4eHh7/wAARCAB4AFoDASIAAhEBAxEB/8QAHAAAAgMBAQEBAAAA
+ AAAAAAAABgcEBQgAAgMB/8QAORAAAQMDAwEGAwYEBwEAAAAAAQIDBAAFEQYSITET
+ IkFRYXEHMpEUFYGhwfAII7HRM0JSYoKywuH/xAAaAQACAwEBAAAAAAAAAAAAAAAE
+ BQEDBgAC/8QAIhEAAgICAgIDAQEAAAAAAAAAAQIAAwQREiETMQUiQVEy/9oADAMB
+ AAIRAxEAPwDOejbio3MgNkoBzx403LRcba9taeHzdQpGaUuhbbJBLqmyCTwFGtAa
+ VssPR+nEauu7bUi6vNlVuhKGQhPQOrHrzgeuaUlx5CB+Q6xAToSzl6G0sbSX7kwL
+ eopSrOdiiD44496A9Tat0fopxVr0xp9i5P7QXJUokkkjkDk4HT69KqNYXW+6mbU8
+ 7NdSEkFSArr1Ph654obVY1d3ajKyOQR1J65rnyFHqGY3x4H+zL25a8WbQVW6JDjP
+ ye6pDaMBOTnA5JxQpMuFyW+p1bq2Gkj+YtTg7VZxnAPhk+H9jV/H0bOdHaMMrCuq
+ ldMDpxnx9arJNlVFugQ5hQSNzfJwXMDk+mfChxcpMZeAKvQg6JNzRh37xeZQQT3X
+ VZx7Cor2oXA2WnFrlbvmLv79vwqxv6mXZS27eypcfHZoUB3lkY6DwAHHl60Jzmih
+ agpO1aSQpOOhzRtaBvcFtOl3qXcGTAccy1hBI7zav05HSruySnWpaXgXMAju8cUu
+ iopOc0XaUk/a2XEqGX2xnOfmT5+4/tU20lRyEUOQzR32S5R3ogSp7flPAzU8qJOQ
+ gkH/AGml7pBa2UDKio5yAPD3o1DM5Q3BSMHn5agN1KCmjPvZbBD7dDLSSgpO4YTk
+ evtV/qeDKuMtx95bi0tNgNZHAx0FRPhszMvsh+DGBb+0OIaLikghIGSceXFNu82O
+ ElhiDDbCGY7ewqV1V6nHiTk/jSkbVN/2NMZCXiSa0+slwJTkqGMefBP61e6f0ehJ
+ S9JRvIGcEdPWmPBs8VkjDaVFI4PlUlcZs90J6jp4Cg2tYjUd1167MEJFvbDHYttb
+ ePLGfegjUejWJOOFpWAccc+PNN+ZGQ03whO7zBoWvZUkJSAULzjjy8qo2yncLBB6
+ Ez9PtAgF+M0hxK14ClJQTsTjqD5nz/pQPfrQzDkFKHVBBBJC8bv3mnjqWKFdqAUg
+ gZ56e9JrV6GG5C1POpMjdykf1JH9Kd4drNqK7l+x3A+Q1jywK/LZNXBmIebJ7p5G
+ cbh4ivcxRWsgDBPgKgrSUmnSDY0YiydK+1EdXw5kxJRD8lYCAchGfA9KbKLlaQgA
+ IGAOM1nbQLjaoY3Faih3apKVYwPP14zTJaS4W0kB7GBj+ef7UEx8balDKD3HL/D3
+ GS3bn5rqBvUVBvHJwTg/9aYU11CXVjvKz1pZfAi8PTtBwpLiW2nj3XCgYTkFQyB+
+ +tMGSHStKgQkEdSOT60lym4nj/JpcKromcHh2OEkJHOec1+sqZQ0FFaNxHOSMV8U
+ Mt56Eq8Sal9kSlISkEEZJ/YoVezuHtoCRnlMvIwFNrUPLAPvmhTUTZ+0jI7oPBJ5
+ omngJwFKaRn/AFdKF7q4ytpSkuIVuB2hKs8+H1ry7danVqd7EXOqloZD6lJWcHOS
+ OlIvV+H7o4GknJV08Qa0VLtbd0SsrAwrPgMUr9caNQzMBbUEhwAjwz9KMwchVbRl
+ V1QOyYo3I6kK5UCRzwc4qysdhTOQp+XJ+zM52IIb3rWrwATkZNXuorGm2x9iSlKX
+ FY2j51gfpk5/D0o6+FFmjSbM/LeLSZCDhhChy2Bz18zjk9ab3ZfCvkIFRhpbZ9h1
+ ATQdrl2/V0i2yUqSSxvA5AXyNpH4E05G4b/Zp/lNdB1UaiTYraHbVdOxSXWn3Iq+
+ OQhbZUOfRTYx71cC4pAA7PpQ75At00V5uMcezgIM/wAKNznLVcrWgl1hlxD2wnhI
+ VkEj6CtGOPI2FeRvA5yoHB/SsY/Ci4XCFeXodskiM+8nBcz/AKT+fU00b5JesUJt
+ 67a67F50ghlKdzh/4p5x6kUHn18rjr2ZocRNVgx4SLuw2ELUDtVwQmgHXPxTmRZS
+ bTp2KX5KuFLKeB6elSPhNLF/t8pDr7jwawQ6pop3pUOD3qB73pq9RLtOfgSUpS+8
+ U9qcbmkjB/DrQCNxPcOCI5hLAsWp75GTPv8AeVoUeUx2lAbfc14RBnWx4NtrW+0V
+ JThQ564HNRYOioc2JHkXPUV0CGUntUInrSHT1BOensKurTp23x3g7EmSRDz3W3Hl
+ upV5Eknj61FjLr3uQFPoCWCGUNs5ABThXeHy+2fqKDtdsibEU9HCSWu6lR88UY3t
+ SlNIyph1lPADeUhIHljIxQhqF5pFvdhKSEoIIUQfDNVI33Ek17WKCY46/duycaDr
+ +3B7QlIPoCDnzoq0tpftUCYiUuLNTne2FHa4Bz+BxQxGbdYuDqHR2oB7iuufbyNO
+ TSEq3tbH5bjPauISlEdPJ3HxIHkP60zvtIUASjHXgSRPEtovpag7FhbbTXaE9Svv
+ YPvtNQlWe4BRwhRGevNGGm2I8y+zIuMuspD7pzk5cPGfLhJou+7GPFsfSrcfHLJu
+ IPlsjnf6mIbBMkRtQx5UUBLq1bBnnG4bc/nWiNKWHTtu7EKtjF2uyk5dkPntClRH
+ PB6e1ZrYc7C4NSWwQhKwoAnJGK2LpK5xpFihutoawGxjAx4dan5Z2TiVjr45OYYG
+ XOm2Psbco9m0krKVKCEbUjjpXiNHSt5TymEOJUTlJOOK+1snQ126S4Xkghas56k+
+ FUDuorPa2Frn3JllalHAWsAkenNJu3PQjBV4jUuHbDbhJEhERtSTzjAOPbFXEWJH
+ jRApDaW0qHQcflS+td3cvSpMqFIcZZZIDLqU8OnxGPEeteXdVSGEGLcApp0HCVf5
+ T/8Aa4gjsz0F5dblreWWC8p6LhtfRSAeF/h4H1oG1SwsnKkqS2fLwHlxX0vV5kMP
+ NywT2e7vc8YzUi6b5EMrUFbSnckmq1GjuS68RqDDVigqIkckgYwOAfKpdx1rZ9Os
+ ogMW9Kp5QNywkZBPr7VGbkFpC21KIGeKhXC222fIEqRHCnU4wsnr70ZXon7+oON+
+ hCX+G569T9aatulxKthaa3Ag7clSijH/ABBptOXRsOKG4Dk0F/CR8N/ekZlKd7yE
+ qzgA93j9T9RUx+NOLyzv6qP9adh+agrMdmqRcwaY5akKQShaMjyNOr4c60UqwtxH
+ FbHW8NoOeFHGBSgblw2U4lRO0X5hWKsLFfGhPaioSGIy1gHnkHPzZ9KtzMfz1616
+ jvCyVx7NM+9x4O3G5R0rcgK3E/4iF8gnzFVGl9PKuN/cn3mEHVuHckEFSUfXgVeJ
+ t70a3mZGc+1d0KKFHOR5g1Y2y7T5K0x0tKjjgKW2wSduPA4xWfqYpvUeOC43CR2X
+ CtUMJPZspSngEgYHtQcdQ2y8Xb7qQESFLJHAyPrRZD0TAl4k3NbriykqDb6uSkjg
+ kDgH0zVvZ9P2S12tcaDFaQgnKlBI3LI8SfHwrn0R9pUNJ6gTfbPHYtLUVre4vn5j
+ nAFTdUkwrQ2RwktJPPtX5qCUlpDzqe8oJLaeeCScAY86HfiXdFJhtRSvKkoSnr5A
+ D9KHC7InssSIMuzAtXBGSrJBqwilSmQfDJJHp0H79aHGipw4HPPvRRAYUpKW0pyT
+ gY9AKIPQkIO9wm+GclMbVcZJJBfy0fYjkfUCm+YbBJPZdaWvwmsTk3UL9zcwI9vQ
+ VZI6uLylA/7H8KcyILxQk7QOOmOlOcNSU7mR+WI8/Uwx8ZdLMWK+BUNKxHfTuAPO
+ 00AllbRCgPDNPH4l3W1XwIhY3Ps7hhIyc4pbW62pVe2oziQ4gOALB6bfGr8TKPi0
+ 35GOR8d5bOQ9xn/CDUwutl+7pCsvso7I5PJHgf0o/gz3o7PYNR0qUk4wpWAPwpMa
+ E09dbbeZM1lvsmQBsUrorkHH0NO2KuPJQysNDK0JJOKSZ6KlpZPRjb469mXxuexL
+ SI9c5ZKFrHHzJSan3GW5AgBIRlWD+NfkOZFhRsBaUYzuAFCWvNWsx4J747ZY2tpB
+ 5PhQgBb1L2JJlVcZ6VT2kLWClLpeXgcd3JA+uKX+rbsJ0tZbO1O7ABr1e7+hlvCD
+ l9acY9+tCfaOvvbACTnJI8KNx8c/6Mgn8hRaFg9nydw8qYek7e8/hTbKluvENspA
+ yVE9cevhQjoqyuyloG0kqIzWpfhpo0aehNXScwPvBxOIjBH+EnHznyUR9M1y0m2z
+ QlGXlpiVEn3LDSGmm7DZotrISp7f9omLA4U4fDPknoKvl3iE2so2JO04znrVVrK7
+ M6esrst9fexwCeVLI4T+vsDWepeo5bsp51c1e5a1KOFEck042EAAmR4tcxdoDT9N
+ uQNU9u6G3ITru7vcFeTkoPqelMvUGh7XcRFuNpiR7c+SOwgowoDJ/wAxGennXV1L
+ FYvoGae4lBzHufKJFbs6X4F1R2Uhg94Hz/UetC07Vka2y1IYUFN5yAMHbXV1e7aV
+ PUS03utnMHuUd8104+sGOgFWOQRwaDrk5dZkv7XJUvcr5OMAetdXV1aLUPqI/S5n
+ 1uQnyWhgAuPKOM0UaJ07Ouk5mHEjOSZTygAhCdxz7V1dVlnagf2erWKIWE1v8K/h
+ zE0lEbmXJKJV0PKW08tsn/0r8hTHQ0UhyVIVlRHU/vpXV1FV1qi9TI3XPdYS5meP
+ jBqNy+3ZxiOrdFjlSW8cbz4q/L8vWl0GMjJb6/7q6uqsnZhVY0Op/9k=
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/issues/issue99-base64_literal_custom_tag.yaml b/src/test/resources/issues/issue99-base64_literal_custom_tag.yaml
new file mode 100644
index 0000000..35910ab
--- /dev/null
+++ b/src/test/resources/issues/issue99-base64_literal_custom_tag.yaml
@@ -0,0 +1,82 @@
+jpegPhoto: !beautiful |
+ /9j/4AAQSkZJRgABAQEASABIAAD/2wBDAAUDBAQEAwUEBAQFBQUGBwwIBwcHBw8L
+ CwkMEQ8SEhEPERETFhwXExQaFRERGCEYGh0dHx8fExciJCIeJBweHx7/2wBDAQUF
+ BQcGBw4ICA4eFBEUHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4e
+ Hh4eHh4eHh4eHh4eHh7/wAARCAB4AFoDASIAAhEBAxEB/8QAHAAAAgMBAQEBAAAA
+ AAAAAAAABgcEBQgAAgMB/8QAORAAAQMDAwEGAwYEBwEAAAAAAQIDBAAFEQYSITET
+ IkFRYXEHMpEUFYGhwfAII7HRM0JSYoKywuH/xAAaAQACAwEBAAAAAAAAAAAAAAAE
+ BQEDBgAC/8QAIhEAAgICAgIDAQEAAAAAAAAAAQIAAwQREiETMQUiQVEy/9oADAMB
+ AAIRAxEAPwDOejbio3MgNkoBzx403LRcba9taeHzdQpGaUuhbbJBLqmyCTwFGtAa
+ VssPR+nEauu7bUi6vNlVuhKGQhPQOrHrzgeuaUlx5CB+Q6xAToSzl6G0sbSX7kwL
+ eopSrOdiiD44496A9Tat0fopxVr0xp9i5P7QXJUokkkjkDk4HT69KqNYXW+6mbU8
+ 7NdSEkFSArr1Ph654obVY1d3ajKyOQR1J65rnyFHqGY3x4H+zL25a8WbQVW6JDjP
+ ye6pDaMBOTnA5JxQpMuFyW+p1bq2Gkj+YtTg7VZxnAPhk+H9jV/H0bOdHaMMrCuq
+ ldMDpxnx9arJNlVFugQ5hQSNzfJwXMDk+mfChxcpMZeAKvQg6JNzRh37xeZQQT3X
+ VZx7Cor2oXA2WnFrlbvmLv79vwqxv6mXZS27eypcfHZoUB3lkY6DwAHHl60Jzmih
+ agpO1aSQpOOhzRtaBvcFtOl3qXcGTAccy1hBI7zav05HSruySnWpaXgXMAju8cUu
+ iopOc0XaUk/a2XEqGX2xnOfmT5+4/tU20lRyEUOQzR32S5R3ogSp7flPAzU8qJOQ
+ gkH/AGml7pBa2UDKio5yAPD3o1DM5Q3BSMHn5agN1KCmjPvZbBD7dDLSSgpO4YTk
+ evtV/qeDKuMtx95bi0tNgNZHAx0FRPhszMvsh+DGBb+0OIaLikghIGSceXFNu82O
+ ElhiDDbCGY7ewqV1V6nHiTk/jSkbVN/2NMZCXiSa0+slwJTkqGMefBP61e6f0ehJ
+ S9JRvIGcEdPWmPBs8VkjDaVFI4PlUlcZs90J6jp4Cg2tYjUd1167MEJFvbDHYttb
+ ePLGfegjUejWJOOFpWAccc+PNN+ZGQ03whO7zBoWvZUkJSAULzjjy8qo2yncLBB6
+ Ez9PtAgF+M0hxK14ClJQTsTjqD5nz/pQPfrQzDkFKHVBBBJC8bv3mnjqWKFdqAUg
+ gZ56e9JrV6GG5C1POpMjdykf1JH9Kd4drNqK7l+x3A+Q1jywK/LZNXBmIebJ7p5G
+ cbh4ivcxRWsgDBPgKgrSUmnSDY0YiydK+1EdXw5kxJRD8lYCAchGfA9KbKLlaQgA
+ IGAOM1nbQLjaoY3Faih3apKVYwPP14zTJaS4W0kB7GBj+ef7UEx8balDKD3HL/D3
+ GS3bn5rqBvUVBvHJwTg/9aYU11CXVjvKz1pZfAi8PTtBwpLiW2nj3XCgYTkFQyB+
+ +tMGSHStKgQkEdSOT60lym4nj/JpcKromcHh2OEkJHOec1+sqZQ0FFaNxHOSMV8U
+ Mt56Eq8Sal9kSlISkEEZJ/YoVezuHtoCRnlMvIwFNrUPLAPvmhTUTZ+0jI7oPBJ5
+ omngJwFKaRn/AFdKF7q4ytpSkuIVuB2hKs8+H1ry7danVqd7EXOqloZD6lJWcHOS
+ OlIvV+H7o4GknJV08Qa0VLtbd0SsrAwrPgMUr9caNQzMBbUEhwAjwz9KMwchVbRl
+ V1QOyYo3I6kK5UCRzwc4qysdhTOQp+XJ+zM52IIb3rWrwATkZNXuorGm2x9iSlKX
+ FY2j51gfpk5/D0o6+FFmjSbM/LeLSZCDhhChy2Bz18zjk9ab3ZfCvkIFRhpbZ9h1
+ ATQdrl2/V0i2yUqSSxvA5AXyNpH4E05G4b/Zp/lNdB1UaiTYraHbVdOxSXWn3Iq+
+ OQhbZUOfRTYx71cC4pAA7PpQ75At00V5uMcezgIM/wAKNznLVcrWgl1hlxD2wnhI
+ VkEj6CtGOPI2FeRvA5yoHB/SsY/Ci4XCFeXodskiM+8nBcz/AKT+fU00b5JesUJt
+ 67a67F50ghlKdzh/4p5x6kUHn18rjr2ZocRNVgx4SLuw2ELUDtVwQmgHXPxTmRZS
+ bTp2KX5KuFLKeB6elSPhNLF/t8pDr7jwawQ6pop3pUOD3qB73pq9RLtOfgSUpS+8
+ U9qcbmkjB/DrQCNxPcOCI5hLAsWp75GTPv8AeVoUeUx2lAbfc14RBnWx4NtrW+0V
+ JThQ564HNRYOioc2JHkXPUV0CGUntUInrSHT1BOensKurTp23x3g7EmSRDz3W3Hl
+ upV5Eknj61FjLr3uQFPoCWCGUNs5ABThXeHy+2fqKDtdsibEU9HCSWu6lR88UY3t
+ SlNIyph1lPADeUhIHljIxQhqF5pFvdhKSEoIIUQfDNVI33Ek17WKCY46/duycaDr
+ +3B7QlIPoCDnzoq0tpftUCYiUuLNTne2FHa4Bz+BxQxGbdYuDqHR2oB7iuufbyNO
+ TSEq3tbH5bjPauISlEdPJ3HxIHkP60zvtIUASjHXgSRPEtovpag7FhbbTXaE9Svv
+ YPvtNQlWe4BRwhRGevNGGm2I8y+zIuMuspD7pzk5cPGfLhJou+7GPFsfSrcfHLJu
+ IPlsjnf6mIbBMkRtQx5UUBLq1bBnnG4bc/nWiNKWHTtu7EKtjF2uyk5dkPntClRH
+ PB6e1ZrYc7C4NSWwQhKwoAnJGK2LpK5xpFihutoawGxjAx4dan5Z2TiVjr45OYYG
+ XOm2Psbco9m0krKVKCEbUjjpXiNHSt5TymEOJUTlJOOK+1snQ126S4Xkghas56k+
+ FUDuorPa2Frn3JllalHAWsAkenNJu3PQjBV4jUuHbDbhJEhERtSTzjAOPbFXEWJH
+ jRApDaW0qHQcflS+td3cvSpMqFIcZZZIDLqU8OnxGPEeteXdVSGEGLcApp0HCVf5
+ T/8Aa4gjsz0F5dblreWWC8p6LhtfRSAeF/h4H1oG1SwsnKkqS2fLwHlxX0vV5kMP
+ NywT2e7vc8YzUi6b5EMrUFbSnckmq1GjuS68RqDDVigqIkckgYwOAfKpdx1rZ9Os
+ ogMW9Kp5QNywkZBPr7VGbkFpC21KIGeKhXC222fIEqRHCnU4wsnr70ZXon7+oON+
+ hCX+G569T9aatulxKthaa3Ag7clSijH/ABBptOXRsOKG4Dk0F/CR8N/ekZlKd7yE
+ qzgA93j9T9RUx+NOLyzv6qP9adh+agrMdmqRcwaY5akKQShaMjyNOr4c60UqwtxH
+ FbHW8NoOeFHGBSgblw2U4lRO0X5hWKsLFfGhPaioSGIy1gHnkHPzZ9KtzMfz1616
+ jvCyVx7NM+9x4O3G5R0rcgK3E/4iF8gnzFVGl9PKuN/cn3mEHVuHckEFSUfXgVeJ
+ t70a3mZGc+1d0KKFHOR5g1Y2y7T5K0x0tKjjgKW2wSduPA4xWfqYpvUeOC43CR2X
+ CtUMJPZspSngEgYHtQcdQ2y8Xb7qQESFLJHAyPrRZD0TAl4k3NbriykqDb6uSkjg
+ kDgH0zVvZ9P2S12tcaDFaQgnKlBI3LI8SfHwrn0R9pUNJ6gTfbPHYtLUVre4vn5j
+ nAFTdUkwrQ2RwktJPPtX5qCUlpDzqe8oJLaeeCScAY86HfiXdFJhtRSvKkoSnr5A
+ D9KHC7InssSIMuzAtXBGSrJBqwilSmQfDJJHp0H79aHGipw4HPPvRRAYUpKW0pyT
+ gY9AKIPQkIO9wm+GclMbVcZJJBfy0fYjkfUCm+YbBJPZdaWvwmsTk3UL9zcwI9vQ
+ VZI6uLylA/7H8KcyILxQk7QOOmOlOcNSU7mR+WI8/Uwx8ZdLMWK+BUNKxHfTuAPO
+ 00AllbRCgPDNPH4l3W1XwIhY3Ps7hhIyc4pbW62pVe2oziQ4gOALB6bfGr8TKPi0
+ 35GOR8d5bOQ9xn/CDUwutl+7pCsvso7I5PJHgf0o/gz3o7PYNR0qUk4wpWAPwpMa
+ E09dbbeZM1lvsmQBsUrorkHH0NO2KuPJQysNDK0JJOKSZ6KlpZPRjb469mXxuexL
+ SI9c5ZKFrHHzJSan3GW5AgBIRlWD+NfkOZFhRsBaUYzuAFCWvNWsx4J747ZY2tpB
+ 5PhQgBb1L2JJlVcZ6VT2kLWClLpeXgcd3JA+uKX+rbsJ0tZbO1O7ABr1e7+hlvCD
+ l9acY9+tCfaOvvbACTnJI8KNx8c/6Mgn8hRaFg9nydw8qYek7e8/hTbKluvENspA
+ yVE9cevhQjoqyuyloG0kqIzWpfhpo0aehNXScwPvBxOIjBH+EnHznyUR9M1y0m2z
+ QlGXlpiVEn3LDSGmm7DZotrISp7f9omLA4U4fDPknoKvl3iE2so2JO04znrVVrK7
+ M6esrst9fexwCeVLI4T+vsDWepeo5bsp51c1e5a1KOFEck042EAAmR4tcxdoDT9N
+ uQNU9u6G3ITru7vcFeTkoPqelMvUGh7XcRFuNpiR7c+SOwgowoDJ/wAxGennXV1L
+ FYvoGae4lBzHufKJFbs6X4F1R2Uhg94Hz/UetC07Vka2y1IYUFN5yAMHbXV1e7aV
+ PUS03utnMHuUd8104+sGOgFWOQRwaDrk5dZkv7XJUvcr5OMAetdXV1aLUPqI/S5n
+ 1uQnyWhgAuPKOM0UaJ07Ouk5mHEjOSZTygAhCdxz7V1dVlnagf2erWKIWE1v8K/h
+ zE0lEbmXJKJV0PKW08tsn/0r8hTHQ0UhyVIVlRHU/vpXV1FV1qi9TI3XPdYS5meP
+ jBqNy+3ZxiOrdFjlSW8cbz4q/L8vWl0GMjJb6/7q6uqsnZhVY0Op/9k=
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/issues/issue99.jpeg b/src/test/resources/issues/issue99.jpeg
new file mode 100644
index 0000000..3258ec5
--- /dev/null
+++ b/src/test/resources/issues/issue99.jpeg
Binary files differ
diff --git a/src/test/resources/javabeans/genericArray-1.yaml b/src/test/resources/javabeans/genericArray-1.yaml
new file mode 100644
index 0000000..bca5836
--- /dev/null
+++ b/src/test/resources/javabeans/genericArray-1.yaml
@@ -0,0 +1,7 @@
+ga:
+ home:
+ - 1
+ - 2
+ - 3
+ name: Array3
+id: ID556677
\ No newline at end of file
diff --git a/src/test/resources/javabeans/house-dump1.yaml b/src/test/resources/javabeans/house-dump1.yaml
new file mode 100644
index 0000000..783d968
--- /dev/null
+++ b/src/test/resources/javabeans/house-dump1.yaml
@@ -0,0 +1,12 @@
+frontDoor:
+ height: 5
+ id: qaz1
+ keytype: qwerty123
+number: 1
+reminders:
+ today: do nothig
+ tomorrow: go shoping
+rooms:
+- name: Hall
+- name: Kitchen
+street: Wall Street
\ No newline at end of file
diff --git a/src/test/resources/javabeans/house-dump2.yaml b/src/test/resources/javabeans/house-dump2.yaml
new file mode 100644
index 0000000..4a3850b
--- /dev/null
+++ b/src/test/resources/javabeans/house-dump2.yaml
@@ -0,0 +1,13 @@
+!!org.yaml.snakeyaml.javabeans.House
+frontDoor:
+ height: 5
+ id: qaz1
+ keytype: qwerty123
+number: 1
+reminders:
+ today: do nothig
+ tomorrow: go shoping
+rooms:
+- name: Hall
+- name: Kitchen
+street: Wall Street
\ No newline at end of file
diff --git a/src/test/resources/javabeans/house-dump3.yaml b/src/test/resources/javabeans/house-dump3.yaml
new file mode 100644
index 0000000..514d921
--- /dev/null
+++ b/src/test/resources/javabeans/house-dump3.yaml
@@ -0,0 +1,12 @@
+frontDoor:
+ height: 5
+ id: qaz1
+ keytype: qwerty123
+number: 1
+reminders:
+ today: do nothig
+ tomorrow: go shoping
+rooms:
+- name: Hall
+- name: Kitchen
+street: Wall Street
diff --git a/src/test/resources/javabeans/issue10-1.yaml b/src/test/resources/javabeans/issue10-1.yaml
new file mode 100644
index 0000000..83ddc87
--- /dev/null
+++ b/src/test/resources/javabeans/issue10-1.yaml
@@ -0,0 +1,9 @@
+!!org.yaml.snakeyaml.issues.issue10.DataSources
+dataSources:
+- &id001 {name: null}
+- !!org.yaml.snakeyaml.issues.issue10.JDBCDataSource
+ name: null
+ parent: *id001
+ password: null
+ url: null
+ username: null
\ No newline at end of file
diff --git a/src/test/resources/javabeans/issue10-2.yaml b/src/test/resources/javabeans/issue10-2.yaml
new file mode 100644
index 0000000..0a83745
--- /dev/null
+++ b/src/test/resources/javabeans/issue10-2.yaml
@@ -0,0 +1,9 @@
+dataSources:
+- &id001
+ name: null
+- !!org.yaml.snakeyaml.issues.issue10.JDBCDataSource
+ name: null
+ parent: *id001
+ password: null
+ url: null
+ username: null
\ No newline at end of file
diff --git a/src/test/resources/javabeans/issue10-3.yaml b/src/test/resources/javabeans/issue10-3.yaml
new file mode 100644
index 0000000..390a9c7
--- /dev/null
+++ b/src/test/resources/javabeans/issue10-3.yaml
@@ -0,0 +1,9 @@
+dataSources:
+- !!org.yaml.snakeyaml.issues.issue10.JDBCDataSource
+ name: null
+ parent: &id001
+ name: null
+ password: null
+ url: null
+ username: null
+- *id001
\ No newline at end of file
diff --git a/src/test/resources/javabeans/mycar-with-global-tag1.yaml b/src/test/resources/javabeans/mycar-with-global-tag1.yaml
new file mode 100644
index 0000000..724d20e
--- /dev/null
+++ b/src/test/resources/javabeans/mycar-with-global-tag1.yaml
@@ -0,0 +1,14 @@
+!!org.yaml.snakeyaml.constructor.MyCar
+plate: 00-FF-Q2
+wheels:
+ ? {brand: Pirelli1, id: 1}
+ : 2009-07-21T21:36:08.085Z
+ ? {brand: Pirelli2, id: 2}
+ : 2009-07-21T21:36:08.086Z
+ ? {brand: Pirelli3, id: 3}
+ : 2009-07-21T21:36:08.087Z
+ ? {brand: Pirelli4, id: 4}
+ : 2009-07-21T21:36:08.088Z
+ ? {brand: Pirelli5, id: 5}
+ : 2009-07-21T21:36:08.089Z
+windows: null
\ No newline at end of file
diff --git a/src/test/resources/org/yaml/snakeyaml/issues/issue318/classpath.properties b/src/test/resources/org/yaml/snakeyaml/issues/issue318/classpath.properties
new file mode 100644
index 0000000..a0ee78c
--- /dev/null
+++ b/src/test/resources/org/yaml/snakeyaml/issues/issue318/classpath.properties
@@ -0,0 +1,2 @@
+runtime_classes_dir=${project.build.outputDirectory}
+test_classes_dir=${project.build.testOutputDirectory}
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 0000000..f97d49f
--- /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 0000000..9139b51
--- /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 0000000..0988b63
--- /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 0000000..13d5087
--- /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 0000000..dcdb16f
--- /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 0000000..36d6519
--- /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 0000000..9db0f64
--- /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 0000000..b662c62
--- /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 0000000..852c314
--- /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 0000000..022446d
--- /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 0000000..3fdb2e2
--- /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 0000000..9ad0344
--- /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 0000000..4fa0f45
--- /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 0000000..05f55b9
--- /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 0000000..bb92fd1
--- /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 0000000..e05dc88
--- /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 0000000..0d93013
--- /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 0000000..e355f18
--- /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 0000000..606ac6b
--- /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 0000000..c5f3840
--- /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 0000000..3eb7919
--- /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 0000000..9eeb0d6
--- /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 0000000..775a51a
--- /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-anchors.canonical b/src/test/resources/pyyaml/duplicate-anchors.canonical
new file mode 100644
index 0000000..257ea26
--- /dev/null
+++ b/src/test/resources/pyyaml/duplicate-anchors.canonical
@@ -0,0 +1,6 @@
+%YAML 1.1
+---
+!!seq [
+ !!str "foo", !!str "foo",
+ !!str "bar", !!str "bar"
+]
diff --git a/src/test/resources/pyyaml/duplicate-anchors.data b/src/test/resources/pyyaml/duplicate-anchors.data
new file mode 100644
index 0000000..8dc8685
--- /dev/null
+++ b/src/test/resources/pyyaml/duplicate-anchors.data
@@ -0,0 +1,4 @@
+- &id foo
+- *id
+- &id bar
+- *id
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 0000000..84deb8f
--- /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 0000000..7e7b4d1
--- /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 0000000..cebc3a1
--- /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 0000000..50c81a0
--- /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 0000000..b34a1d6
--- /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 0000000..9b72390
--- /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 0000000..473bed5
--- /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 0000000..b6b42ba
--- /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 0000000..2a5df00
--- /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 0000000..ce663b6
--- /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 0000000..28a6cf1
--- /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 0000000..e69de29
--- /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 0000000..f8dba8d
--- /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 0000000..235c899
--- /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 0000000..c6c0e95
--- /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 0000000..b7ca593
--- /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 0000000..0cbab89
--- /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 0000000..8ce575e
--- /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 0000000..82aed98
--- /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 0000000..36ceca3
--- /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 0000000..891ee37
--- /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 0000000..62c54d3
--- /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 0000000..7b3171e
--- /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 0000000..08074ea
--- /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 0000000..480dc2e
--- /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 0000000..46c6f8b
--- /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 0000000..25fac24
--- /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 0000000..efd1716
--- /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 0000000..524d5db
--- /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 0000000..f2e3079
--- /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 0000000..da9b471
--- /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 0000000..efd7ce5
--- /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 0000000..f8c9a5c
--- /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 0000000..d44d376
--- /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 0000000..fcf7d0f
--- /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 0000000..bfc4ff0
--- /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 0000000..3d2a814
--- /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 0000000..798abba
--- /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 0000000..16a6db1
--- /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 0000000..03687b0
--- /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 0000000..03687b0
--- /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 0000000..0892eb6
--- /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 0000000..153fd88
--- /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 0000000..3732a06
--- /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 0000000..a95ab76
--- /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 0000000..614ec9f
--- /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 0000000..a3cd12f
--- /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 0000000..eefb6ec
--- /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-item-without-trailing-break.loader-error b/src/test/resources/pyyaml/invalid-item-without-trailing-break.loader-error
new file mode 100644
index 0000000..fdcf6c6
--- /dev/null
+++ b/src/test/resources/pyyaml/invalid-item-without-trailing-break.loader-error
@@ -0,0 +1,2 @@
+-
+-0
\ No newline at end of file
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 0000000..fc3c284
--- /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 0000000..8e88615
--- /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 0000000..2863392
--- /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 0000000..c377dfb
--- /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 0000000..2a4f50d
--- /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 0000000..42d19ae
--- /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 0000000..31389ea
--- /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 0000000..f8d7704
--- /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 0000000..a58deec
--- /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 0000000..76ef7ae
--- /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 0000000..bb81c60
--- /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 0000000..a68cd38
--- /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 0000000..3a36700
--- /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 0000000..42b5d7e
--- /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 0000000..0cb482c
--- /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 0000000..d5df9a2
--- /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 0000000..ef0d143
--- /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 0000000..d1831d5
--- /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 0000000..06c7f0e
--- /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 0000000..a6ecb36
--- /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 0000000..b89e8f6
--- /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 0000000..f2e4cb8
--- /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 0000000..06307e0
--- /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 0000000..15111c3
--- /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 0000000..15111c3
--- /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 0000000..e9b4e3a
--- /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 0000000..6aa7740
--- /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 0000000..345e784
--- /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 0000000..b35ca82
--- /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 0000000..7c2b49f
--- /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 0000000..bae714f
--- /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 0000000..dd01948
--- /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 0000000..3cb5579
--- /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 0000000..e455bbc
--- /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 0000000..399eb17
--- /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 0000000..18e16e3
--- /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 0000000..5ff065c
--- /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 0000000..02d4d37
--- /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 0000000..be63571
--- /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 0000000..1ea921c
--- /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 0000000..c725ec8
--- /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 0000000..8bd1403
--- /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 0000000..750d973
--- /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 0000000..07b1500
--- /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 0000000..563e3b3
--- /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 0000000..384c62f
--- /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 0000000..ad12528
--- /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 0000000..37da060
--- /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 0000000..fe1bc6c
--- /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 0000000..a296404
--- /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 0000000..fe01734
--- /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 0000000..32c40f4
--- /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 0000000..4a0e8a8
--- /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 0000000..3c70543
--- /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 0000000..79f08b7
--- /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 0000000..5856454
--- /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 0000000..692a329
--- /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 0000000..9c558e3
--- /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 0000000..438bc04
--- /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 0000000..2eb4f5a
--- /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 0000000..d12e671
--- /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 0000000..ce44cac
--- /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 0000000..7b7ec94
--- /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 0000000..e4e381b
--- /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 0000000..656d628
--- /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 0000000..89815f2
--- /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 0000000..430f6b3
--- /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 0000000..9cb9815
--- /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 0000000..cdd7770
--- /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 0000000..3f6f1ab
--- /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 0000000..7a957b2
--- /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 0000000..a1a5eef
--- /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 0000000..bc711d5
--- /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 0000000..ed48883
--- /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 0000000..05e102d
--- /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 0000000..7d2c03d
--- /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 0000000..e264180
--- /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 0000000..b2ec10e
--- /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 0000000..61808f6
--- /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 0000000..26caa2b
--- /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 0000000..9123ce2
--- /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 0000000..fe24203
--- /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 0000000..1fc33f9
--- /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 0000000..ea21e50
--- /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 0000000..13fb656
--- /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 0000000..7456c05
--- /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 0000000..59943de
--- /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 0000000..7456c05
--- /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 0000000..80b89a6
--- /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 0000000..31354ec
--- /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 0000000..9f66d88
--- /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 0000000..e4e381b
--- /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 0000000..3e899c0
--- /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 0000000..db65540
--- /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 0000000..e0a8bfa
--- /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 0000000..83b31dc
--- /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 0000000..bf69de6
--- /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 0000000..5bda68f
--- /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 0000000..1d4897f
--- /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 0000000..db65540
--- /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 0000000..dec6a56
--- /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 0000000..aeccbaf
--- /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 0000000..aaac185
--- /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 0000000..aeccbaf
--- /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 0000000..5dbd992
--- /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 0000000..9ac54aa
--- /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 0000000..1180757
--- /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 0000000..039c385
--- /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 0000000..769ac31
--- /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 0000000..b700236
--- /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 0000000..3143763
--- /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 0000000..7bee492
--- /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 0000000..4625739
--- /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 0000000..2dc1c25
--- /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 0000000..a5c8dc8
--- /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 0000000..8d5e1bc
--- /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 0000000..3525062
--- /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 0000000..0823f74
--- /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 0000000..780d25b
--- /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 0000000..5ebbb04
--- /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 0000000..0cd90a2
--- /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 0000000..fb74866
--- /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 0000000..a143a73
--- /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 0000000..4661f33
--- /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 0000000..00c9723
--- /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 0000000..df33847
--- /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 0000000..62524c0
--- /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 0000000..4f30c11
--- /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 0000000..7a1f9b3
--- /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 0000000..dc3732a
--- /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 0000000..97eb3a3
--- /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 0000000..610bd68
--- /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 0000000..04ebf69
--- /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 0000000..597e3de
--- /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 0000000..a43431b
--- /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 0000000..a4caf91
--- /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 0000000..fc25bef
--- /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 0000000..b448b75
--- /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 0000000..7c3ad7f
--- /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 0000000..90c1c5c
--- /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 0000000..fce7951
--- /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 0000000..4bff01c
--- /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 0000000..d6e8ce4
--- /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 0000000..7bf12b6
--- /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 0000000..f17ec92
--- /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 0000000..6134ba1
--- /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 0000000..ff741e5
--- /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 0000000..ec26902
--- /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 0000000..9db0912
--- /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 0000000..ec26902
--- /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 0000000..86308dd
--- /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 0000000..8da431d
--- /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 0000000..37613f5
--- /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 0000000..513d07a
--- /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 0000000..2f62d08
--- /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 0000000..11357e4
--- /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 0000000..130cfa7
--- /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 0000000..cc72bc8
--- /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 0000000..f2896ed
--- /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 0000000..8c8c48d
--- /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 0000000..2113eb6
--- /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 0000000..cb7dd1c
--- /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 0000000..c8b7322
--- /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 0000000..4bfa07a
--- /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 0000000..cb7dd1c
--- /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 0000000..50f5ab9
--- /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 0000000..7276eae
--- /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 0000000..bddf616
--- /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 0000000..d9854cb
--- /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 0000000..fa086df
--- /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 0000000..9d42ec3
--- /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 0000000..fe917d8
--- /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 0000000..2d36d0e
--- /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 0000000..703aa7b
--- /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 0000000..e2c6d9e
--- /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 0000000..32d9e94
--- /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 0000000..1209d47
--- /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 0000000..1db650a
--- /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 0000000..6939b39
--- /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 0000000..d11302d
--- /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 0000000..efc116f
--- /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 0000000..3807d57
--- /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 0000000..04bcffc
--- /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 0000000..43250db
--- /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 0000000..5af71e9
--- /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 0000000..ba7ec63
--- /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 0000000..69e4161
--- /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 0000000..48986ec
--- /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 0000000..dd6f76e
--- /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 0000000..600d179
--- /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 0000000..be7ea8f
--- /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 0000000..8e51f52
--- /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 0000000..f7d1b01
--- /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 0000000..a5c710a
--- /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 0000000..93576ed
--- /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 0000000..8580010
--- /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 0000000..e2f43d9
--- /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 0000000..98aa565
--- /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 0000000..d3f8b1a
--- /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 0000000..757a93d
--- /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 0000000..3805daf
--- /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 0000000..69da042
--- /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 0000000..8281c5e
--- /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 0000000..72acc56
--- /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 0000000..dd6f76e
--- /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 0000000..600d179
--- /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 0000000..93899f4
--- /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 0000000..3d4c6b7
--- /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 0000000..618bb7b
--- /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 0000000..ebe663a
--- /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 0000000..11db439
--- /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 0000000..2fbb1f7
--- /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 0000000..76f028e
--- /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 0000000..7c86bcf
--- /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 0000000..e71a548
--- /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 0000000..9e83eaf
--- /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 0000000..6f8f41a
--- /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 0000000..d84883d
--- /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 0000000..658c6df
--- /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 0000000..e0b914d
--- /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 0000000..fa46632
--- /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 0000000..313a91b
--- /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 0000000..24d1052
--- /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 0000000..624c30e
--- /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 0000000..5028772
--- /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 0000000..b038078
--- /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 0000000..e71a548
--- /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 0000000..755b54a
--- /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 0000000..06abdb5
--- /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 0000000..aa4d458
--- /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 0000000..658c6df
--- /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 0000000..52171df
--- /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 0000000..2028d04
--- /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 0000000..0e41449
--- /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 0000000..4eb222c
--- /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 0000000..5efa873
--- /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 0000000..d8e6dce
--- /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 0000000..b9a3ac5
--- /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 0000000..e71a548
--- /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 0000000..b156386
--- /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 0000000..97f2316
--- /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 0000000..df02040
--- /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 0000000..e6863b0
--- /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 0000000..06abdb5
--- /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 0000000..473beb9
--- /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 0000000..68cb70d
--- /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 0000000..97bc46c
--- /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 0000000..f21428f
--- /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 0000000..68c5d7c
--- /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 0000000..3e828d7
--- /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 0000000..f0e589d
--- /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 0000000..d03bef5
--- /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 0000000..39bee04
--- /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 0000000..0fdd14f
--- /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 0000000..c1bbcd2
--- /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 0000000..0dd51eb
--- /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 0000000..c4444ca
--- /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 0000000..8972d2b
--- /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 0000000..45a99b0
--- /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 0000000..de0b64b
--- /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 0000000..9d2327b
--- /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 0000000..f6303a1
--- /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 0000000..3029a11
--- /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 0000000..f28555a
--- /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 0000000..3029a11
--- /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 0000000..f28555a
--- /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 0000000..3029a11
--- /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 0000000..f28555a
--- /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 0000000..0980789
--- /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 0000000..82e611f
--- /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 0000000..fc37db1
--- /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 0000000..a4d8c36
--- /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 0000000..fc37db1
--- /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 0000000..a4d8c36
--- /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 0000000..fc37db1
--- /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 0000000..a4d8c36
--- /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 0000000..fc37db1
--- /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 0000000..a4d8c36
--- /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 0000000..d08cdd4
--- /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 0000000..e668d38
--- /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 0000000..82fe0d9
--- /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 0000000..3b23351
--- /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 0000000..1443395
--- /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 0000000..9e15f83
--- /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 0000000..ae486a3
--- /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 0000000..2905b0d
--- /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 0000000..07cc0c9
--- /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 0000000..f19a99e
--- /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 0000000..d9986c2
--- /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 0000000..860ba25
--- /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 0000000..ec74230
--- /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 0000000..ff943fb
--- /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 0000000..55bd788
--- /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 0000000..4d9827b
--- /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 0000000..4d55e21
--- /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 0000000..016fb64
--- /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 0000000..0888b05
--- /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 0000000..7309544
--- /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 0000000..9f05568
--- /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 0000000..a95dd40
--- /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 0000000..5521443
--- /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 0000000..e183c50
--- /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 0000000..b5b97db
--- /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 0000000..e87c880
--- /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 0000000..7f5995c
--- /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 0000000..85fbbd0
--- /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 0000000..d675cfd
--- /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 0000000..7cbdb7c
--- /dev/null
+++ b/src/test/resources/pyyaml/str.data
@@ -0,0 +1 @@
+- abcd
diff --git a/src/test/resources/pyyaml/tab-in-scalar.canonical b/src/test/resources/pyyaml/tab-in-scalar.canonical
new file mode 100644
index 0000000..d5bc00d
--- /dev/null
+++ b/src/test/resources/pyyaml/tab-in-scalar.canonical
@@ -0,0 +1,3 @@
+%YAML 1.1
+---
+"L\tS"
\ No newline at end of file
diff --git a/src/test/resources/pyyaml/tab-in-scalar.data b/src/test/resources/pyyaml/tab-in-scalar.data
new file mode 100644
index 0000000..13a6322
--- /dev/null
+++ b/src/test/resources/pyyaml/tab-in-scalar.data
@@ -0,0 +1 @@
+L S
diff --git a/src/test/resources/pyyaml/tags.events b/src/test/resources/pyyaml/tags.events
new file mode 100644
index 0000000..bb93dce
--- /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 0000000..cf257b4
--- /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 0000000..721d290
--- /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 0000000..7d214ce
--- /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 0000000..d748e37
--- /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 0000000..8c82077
--- /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 0000000..8537429
--- /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 0000000..9469103
--- /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 0000000..9a37ccc
--- /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 0000000..82ba335
--- /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/value.data b/src/test/resources/pyyaml/value.data
new file mode 100644
index 0000000..c5b7680
--- /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 0000000..a4bb3f8
--- /dev/null
+++ b/src/test/resources/pyyaml/yaml.data
@@ -0,0 +1,3 @@
+- !!yaml '!'
+- !!yaml '&'
+- !!yaml '*'
diff --git a/src/test/resources/reader/large.yaml b/src/test/resources/reader/large.yaml
new file mode 100644
index 0000000..12d5495
--- /dev/null
+++ b/src/test/resources/reader/large.yaml
@@ -0,0 +1,182 @@
+- !!map
+ id: id0
+ list: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
+ map: {'3': 3, '2': 2, '1': 1, '0': 0, '7': 7, '6': 6, '5': 5, '4': 4, '9': 9, '8': 8}
+- !!map
+ id: id1
+ list: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10']
+ map: {'3': 4, '2': 3, '1': 2, '0': 1, '7': 8, '6': 7, '5': 6, '4': 5, '9': 10, '8': 9}
+- !!map
+ id: id2
+ list: ['2', '3', '4', '5', '6', '7', '8', '9', '10', '11']
+ map: {'3': 5, '2': 4, '1': 3, '0': 2, '7': 9, '6': 8, '5': 7, '4': 6, '9': 11, '8': 10}
+- !!map
+ id: id3
+ list: ['3', '4', '5', '6', '7', '8', '9', '10', '11', '12']
+ map: {'3': 6, '2': 5, '1': 4, '0': 3, '7': 10, '6': 9, '5': 8, '4': 7, '9': 12,
+ '8': 11}
+- !!map
+ id: id4
+ list: ['4', '5', '6', '7', '8', '9', '10', '11', '12', '13']
+ map: {'3': 7, '2': 6, '1': 5, '0': 4, '7': 11, '6': 10, '5': 9, '4': 8, '9': 13,
+ '8': 12}
+- !!map
+ id: id5
+ list: ['5', '6', '7', '8', '9', '10', '11', '12', '13', '14']
+ map: {'3': 8, '2': 7, '1': 6, '0': 5, '7': 12, '6': 11, '5': 10, '4': 9, '9': 14,
+ '8': 13}
+- !!map
+ id: id6
+ list: ['6', '7', '8', '9', '10', '11', '12', '13', '14', '15']
+ map: {'3': 9, '2': 8, '1': 7, '0': 6, '7': 13, '6': 12, '5': 11, '4': 10, '9': 15,
+ '8': 14}
+- !!map
+ id: id7
+ list: ['7', '8', '9', '10', '11', '12', '13', '14', '15', '16']
+ map: {'3': 10, '2': 9, '1': 8, '0': 7, '7': 14, '6': 13, '5': 12, '4': 11, '9': 16,
+ '8': 15}
+- !!map
+ id: id8
+ list: ['8', '9', '10', '11', '12', '13', '14', '15', '16', '17']
+ map: {'3': 11, '2': 10, '1': 9, '0': 8, '7': 15, '6': 14, '5': 13, '4': 12, '9': 17,
+ '8': 16}
+- !!map
+ id: id9
+ list: ['9', '10', '11', '12', '13', '14', '15', '16', '17', '18']
+ map: {'3': 12, '2': 11, '1': 10, '0': 9, '7': 16, '6': 15, '5': 14, '4': 13, '9': 18,
+ '8': 17}
+- !!map
+ id: id10
+ list: ['10', '11', '12', '13', '14', '15', '16', '17', '18', '19']
+ map: {'3': 13, '2': 12, '1': 11, '0': 10, '7': 17, '6': 16, '5': 15, '4': 14, '9': 19,
+ '8': 18}
+- !!map
+ id: id11
+ list: ['11', '12', '13', '14', '15', '16', '17', '18', '19', '20']
+ map: {'3': 14, '2': 13, '1': 12, '0': 11, '7': 18, '6': 17, '5': 16, '4': 15, '9': 20,
+ '8': 19}
+- !!map
+ id: id12
+ list: ['12', '13', '14', '15', '16', '17', '18', '19', '20', '21']
+ map: {'3': 15, '2': 14, '1': 13, '0': 12, '7': 19, '6': 18, '5': 17, '4': 16, '9': 21,
+ '8': 20}
+- !!map
+ id: id13
+ list: ['13', '14', '15', '16', '17', '18', '19', '20', '21', '22']
+ map: {'3': 16, '2': 15, '1': 14, '0': 13, '7': 20, '6': 19, '5': 18, '4': 17, '9': 22,
+ '8': 21}
+- !!map
+ id: id14
+ list: ['14', '15', '16', '17', '18', '19', '20', '21', '22', '23']
+ map: {'3': 17, '2': 16, '1': 15, '0': 14, '7': 21, '6': 20, '5': 19, '4': 18, '9': 23,
+ '8': 22}
+- !!map
+ id: id15
+ list: ['15', '16', '17', '18', '19', '20', '21', '22', '23', '24']
+ map: {'3': 18, '2': 17, '1': 16, '0': 15, '7': 22, '6': 21, '5': 20, '4': 19, '9': 24,
+ '8': 23}
+- !!map
+ id: id16
+ list: ['16', '17', '18', '19', '20', '21', '22', '23', '24', '25']
+ map: {'3': 19, '2': 18, '1': 17, '0': 16, '7': 23, '6': 22, '5': 21, '4': 20, '9': 25,
+ '8': 24}
+- !!map
+ id: id17
+ list: ['17', '18', '19', '20', '21', '22', '23', '24', '25', '26']
+ map: {'3': 20, '2': 19, '1': 18, '0': 17, '7': 24, '6': 23, '5': 22, '4': 21, '9': 26,
+ '8': 25}
+- !!map
+ id: id18
+ list: ['18', '19', '20', '21', '22', '23', '24', '25', '26', '27']
+ map: {'3': 21, '2': 20, '1': 19, '0': 18, '7': 25, '6': 24, '5': 23, '4': 22, '9': 27,
+ '8': 26}
+- !!map
+ id: id19
+ list: ['19', '20', '21', '22', '23', '24', '25', '26', '27', '28']
+ map: {'3': 22, '2': 21, '1': 20, '0': 19, '7': 26, '6': 25, '5': 24, '4': 23, '9': 28,
+ '8': 27}
+- !!map
+ id: id20
+ list: ['20', '21', '22', '23', '24', '25', '26', '27', '28', '29']
+ map: {'3': 23, '2': 22, '1': 21, '0': 20, '7': 27, '6': 26, '5': 25, '4': 24, '9': 29,
+ '8': 28}
+- !!map
+ id: id21
+ list: ['21', '22', '23', '24', '25', '26', '27', '28', '29', '30']
+ map: {'3': 24, '2': 23, '1': 22, '0': 21, '7': 28, '6': 27, '5': 26, '4': 25, '9': 30,
+ '8': 29}
+- !!map
+ id: id22
+ list: ['22', '23', '24', '25', '26', '27', '28', '29', '30', '31']
+ map: {'3': 25, '2': 24, '1': 23, '0': 22, '7': 29, '6': 28, '5': 27, '4': 26, '9': 31,
+ '8': 30}
+- !!map
+ id: id23
+ list: ['23', '24', '25', '26', '27', '28', '29', '30', '31', '32']
+ map: {'3': 26, '2': 25, '1': 24, '0': 23, '7': 30, '6': 29, '5': 28, '4': 27, '9': 32,
+ '8': 31}
+- !!map
+ id: id24
+ list: ['24', '25', '26', '27', '28', '29', '30', '31', '32', '33']
+ map: {'3': 27, '2': 26, '1': 25, '0': 24, '7': 31, '6': 30, '5': 29, '4': 28, '9': 33,
+ '8': 32}
+- !!map
+ id: id25
+ list: ['25', '26', '27', '28', '29', '30', '31', '32', '33', '34']
+ map: {'3': 28, '2': 27, '1': 26, '0': 25, '7': 32, '6': 31, '5': 30, '4': 29, '9': 34,
+ '8': 33}
+- !!map
+ id: id26
+ list: ['26', '27', '28', '29', '30', '31', '32', '33', '34', '35']
+ map: {'3': 29, '2': 28, '1': 27, '0': 26, '7': 33, '6': 32, '5': 31, '4': 30, '9': 35,
+ '8': 34}
+- !!map
+ id: id27
+ list: ['27', '28', '29', '30', '31', '32', '33', '34', '35', '36']
+ map: {'3': 30, '2': 29, '1': 28, '0': 27, '7': 34, '6': 33, '5': 32, '4': 31, '9': 36,
+ '8': 35}
+- !!map
+ id: id28
+ list: ['28', '29', '30', '31', '32', '33', '34', '35', '36', '37']
+ map: {'3': 31, '2': 30, '1': 29, '0': 28, '7': 35, '6': 34, '5': 33, '4': 32, '9': 37,
+ '8': 36}
+- !!map
+ id: id29
+ list: ['29', '30', '31', '32', '33', '34', '35', '36', '37', '38']
+ map: {'3': 32, '2': 31, '1': 30, '0': 29, '7': 36, '6': 35, '5': 34, '4': 33, '9': 38,
+ '8': 37}
+- !!map
+ id: id30
+ list: ['30', '31', '32', '33', '34', '35', '36', '37', '38', '39']
+ map: {'3': 33, '2': 32, '1': 31, '0': 30, '7': 37, '6': 36, '5': 35, '4': 34, '9': 39,
+ '8': 38}
+- !!map
+ id: id31
+ list: ['31', '32', '33', '34', '35', '36', '37', '38', '39', '40']
+ map: {'3': 34, '2': 33, '1': 32, '0': 31, '7': 38, '6': 37, '5': 36, '4': 35, '9': 40,
+ '8': 39}
+- !!map
+ id: id32
+ list: ['32', '33', '34', '35', '36', '37', '38', '39', '40', '41']
+ map: {'3': 35, '2': 34, '1': 33, '0': 32, '7': 39, '6': 38, '5': 37, '4': 36, '9': 41,
+ '8': 40}
+- !!map
+ id: id33
+ list: ['33', '34', '35', '36', '37', '38', '39', '40', '41', '42']
+ map: {'3': 36, '2': 35, '1': 34, '0': 33, '7': 40, '6': 39, '5': 38, '4': 37, '9': 42,
+ '8': 41}
+- !!map
+ id: id34
+ list: ['34', '35', '36', '37', '38', '39', '40', '41', '42', '43']
+ map: {'3': 37, '2': 36, '1': 35, '0': 34, '7': 41, '6': 40, '5': 39, '4': 38, '9': 43,
+ '8': 42}
+- !!map
+ id: id35
+ list: ['35', '36', '37', '38', '39', '40', '41', '42', '43', '44']
+ map: {'3': 38, '2': 37, '1': 36, '0': 35, '7': 42, '6': 41, '5': 40, '4': 39, '9': 44,
+ '8': 43}
+- !!map
+ id: id36
+ list: ['36', '37', '38', '39', '40', '41', '42', '43', '44', '45']
+ map: {'3': 39, '2': 38, '1': 37, '0': 36, '7': 43, '6': 42, '5': 41, '4': 40, '9': 45,
+ '8': 44}
diff --git a/src/test/resources/reader/unicode-16be.txt b/src/test/resources/reader/unicode-16be.txt
new file mode 100644
index 0000000..18e8f25
--- /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 0000000..2f84586
--- /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 0000000..b0540d2
--- /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/recursive/beanring-3.yaml b/src/test/resources/recursive/beanring-3.yaml
new file mode 100644
index 0000000..eb97a4e
--- /dev/null
+++ b/src/test/resources/recursive/beanring-3.yaml
@@ -0,0 +1,25 @@
+&id001 !!org.yaml.snakeyaml.recursive.Human
+bankAccountOwner:
+ bankAccountOwner:
+ bankAccountOwner: *id001
+ birthPlace: null
+ birthday: null
+ children: !!set {}
+ father: null
+ mother: null
+ name: Man 3
+ partner: null
+ birthPlace: null
+ birthday: null
+ children: !!set {}
+ father: null
+ mother: null
+ name: Man 2
+ partner: null
+birthPlace: null
+birthday: null
+children: !!set {}
+father: null
+mother: null
+name: Man 1
+partner: null
\ No newline at end of file
diff --git a/src/test/resources/recursive/generics/beanring-3.yaml b/src/test/resources/recursive/generics/beanring-3.yaml
new file mode 100644
index 0000000..56b9207
--- /dev/null
+++ b/src/test/resources/recursive/generics/beanring-3.yaml
@@ -0,0 +1,25 @@
+&id001 !!org.yaml.snakeyaml.recursive.generics.HumanGen
+bankAccountOwner:
+ bankAccountOwner:
+ bankAccountOwner: *id001
+ birthPlace: null
+ birthday: null
+ children: !!set {}
+ father: null
+ mother: null
+ name: Man 3
+ partner: null
+ birthPlace: null
+ birthday: null
+ children: !!set {}
+ father: null
+ mother: null
+ name: Man 2
+ partner: null
+birthPlace: null
+birthday: null
+children: !!set {}
+father: null
+mother: null
+name: Man 1
+partner: null
\ No newline at end of file
diff --git a/src/test/resources/recursive/generics/no-children-1.yaml b/src/test/resources/recursive/generics/no-children-1.yaml
new file mode 100644
index 0000000..cef7c7b
--- /dev/null
+++ b/src/test/resources/recursive/generics/no-children-1.yaml
@@ -0,0 +1,17 @@
+&id001 !!org.yaml.snakeyaml.recursive.generics.HumanGen
+bankAccountOwner: *id001
+birthPlace: Leningrad
+birthday: 1970-01-12T13:46:40Z
+children: !!set {}
+father: null
+mother: null
+name: Father
+partner:
+ bankAccountOwner: *id001
+ birthPlace: Saint-Petersburg
+ birthday: 1973-03-03T09:46:40Z
+ children: !!set {}
+ father: null
+ mother: null
+ name: Mother
+ partner: *id001
\ No newline at end of file
diff --git a/src/test/resources/recursive/generics/no-children-2.yaml b/src/test/resources/recursive/generics/no-children-2.yaml
new file mode 100644
index 0000000..fd31206
--- /dev/null
+++ b/src/test/resources/recursive/generics/no-children-2.yaml
@@ -0,0 +1,17 @@
+&id001
+bankAccountOwner: *id001
+birthPlace: Leningrad
+birthday: 1970-01-12T13:46:40Z
+children: !!set {}
+father: null
+mother: null
+name: Father
+partner:
+ bankAccountOwner: *id001
+ birthPlace: Saint-Petersburg
+ birthday: 1973-03-03T09:46:40Z
+ children: !!set {}
+ father: null
+ mother: null
+ name: Mother
+ partner: *id001
\ No newline at end of file
diff --git a/src/test/resources/recursive/generics/with-children-2.yaml b/src/test/resources/recursive/generics/with-children-2.yaml
new file mode 100644
index 0000000..dcc9144
--- /dev/null
+++ b/src/test/resources/recursive/generics/with-children-2.yaml
@@ -0,0 +1,35 @@
+&id002
+bankAccountOwner: &id001
+ bankAccountOwner: *id001
+ birthPlace: Leningrad
+ birthday: 1970-01-12T13:46:40Z
+ children: &id003
+ *id002: son
+ ? bankAccountOwner: *id001
+ birthPlace: New York
+ birthday: 1983-04-24T02:40:00Z
+ children: {}
+ father: *id001
+ mother: &id004
+ bankAccountOwner: *id001
+ birthPlace: Saint-Petersburg
+ birthday: 1973-03-03T09:46:40Z
+ children: *id003
+ father: null
+ mother: null
+ name: Mother
+ partner: *id001
+ name: Daughter
+ partner: null
+ : daughter
+ father: null
+ mother: null
+ name: Father
+ partner: *id004
+birthPlace: Munich
+birthday: 1979-10-28T23:06:40Z
+children: {}
+father: *id001
+mother: *id004
+name: Son
+partner: null
\ No newline at end of file
diff --git a/src/test/resources/recursive/generics/with-children-3.yaml b/src/test/resources/recursive/generics/with-children-3.yaml
new file mode 100644
index 0000000..0172893
--- /dev/null
+++ b/src/test/resources/recursive/generics/with-children-3.yaml
@@ -0,0 +1,35 @@
+&id002 !!org.yaml.snakeyaml.recursive.generics.HumanGen3
+bankAccountOwner: &id001
+ bankAccountOwner: *id001
+ birthPlace: Leningrad
+ birthday: 1970-01-12T13:46:40Z
+ children: &id003
+ - *id002
+ - !!org.yaml.snakeyaml.recursive.generics.HumanGen3
+ bankAccountOwner: *id001
+ birthPlace: New York
+ birthday: 1983-04-24T02:40:00Z
+ children: []
+ father: *id001
+ mother: &id004
+ bankAccountOwner: *id001
+ birthPlace: Saint-Petersburg
+ birthday: 1973-03-03T09:46:40Z
+ children: *id003
+ father: null
+ mother: null
+ name: Mother
+ partner: *id001
+ name: Daughter
+ partner: null
+ father: null
+ mother: null
+ name: Father
+ partner: *id004
+birthPlace: Munich
+birthday: 1979-10-28T23:06:40Z
+children: []
+father: *id001
+mother: *id004
+name: Son
+partner: null
diff --git a/src/test/resources/recursive/generics/with-children-as-list.yaml b/src/test/resources/recursive/generics/with-children-as-list.yaml
new file mode 100644
index 0000000..54558ba
--- /dev/null
+++ b/src/test/resources/recursive/generics/with-children-as-list.yaml
@@ -0,0 +1,35 @@
+&id002
+- !!org.yaml.snakeyaml.recursive.generics.HumanGen3
+ bankAccountOwner: &id001
+ bankAccountOwner: *id001
+ birthPlace: Leningrad
+ birthday: 1970-01-12T13:46:40Z
+ children: *id002
+ father: null
+ mother: null
+ name: Father
+ partner: &id003
+ bankAccountOwner: *id001
+ birthPlace: Saint-Petersburg
+ birthday: 1973-03-03T09:46:40Z
+ children: *id002
+ father: null
+ mother: null
+ name: Mother
+ partner: *id001
+ birthPlace: Munich
+ birthday: 1979-10-28T23:06:40Z
+ children: []
+ father: *id001
+ mother: *id003
+ name: Son
+ partner: null
+- !!org.yaml.snakeyaml.recursive.generics.HumanGen3
+ bankAccountOwner: *id001
+ birthPlace: New York
+ birthday: 1983-04-24T02:40:00Z
+ children: []
+ father: *id001
+ mother: *id003
+ name: Daughter
+ partner: null
diff --git a/src/test/resources/recursive/generics/with-children-as-map.yaml b/src/test/resources/recursive/generics/with-children-as-map.yaml
new file mode 100644
index 0000000..538abea
--- /dev/null
+++ b/src/test/resources/recursive/generics/with-children-as-map.yaml
@@ -0,0 +1,37 @@
+&id002 !!java.util.LinkedHashMap
+? !!org.yaml.snakeyaml.recursive.generics.HumanGen2
+ bankAccountOwner: &id001 !!org.yaml.snakeyaml.recursive.generics.HumanGen2
+ bankAccountOwner: *id001
+ birthPlace: Leningrad
+ birthday: 1970-01-12T13:46:40Z
+ children: *id002
+ father: null
+ mother: null
+ name: Father
+ partner: &id003 !!org.yaml.snakeyaml.recursive.generics.HumanGen2
+ bankAccountOwner: *id001
+ birthPlace: Saint-Petersburg
+ birthday: 1973-03-03T09:46:40Z
+ children: *id002
+ father: null
+ mother: null
+ name: Mother
+ partner: *id001
+ birthPlace: Munich
+ birthday: 1979-10-28T23:06:40Z
+ children: !!java.util.LinkedHashMap {}
+ father: *id001
+ mother: *id003
+ name: Son
+ partner: null
+: This is My Son
+? !!org.yaml.snakeyaml.recursive.generics.HumanGen2
+ bankAccountOwner: *id001
+ birthPlace: New York
+ birthday: 1983-04-24T02:40:00Z
+ children: !!java.util.LinkedHashMap {}
+ father: *id001
+ mother: *id003
+ name: Daughter
+ partner: null
+: This Is My Daughter
\ No newline at end of file
diff --git a/src/test/resources/recursive/generics/with-children-as-set.yaml b/src/test/resources/recursive/generics/with-children-as-set.yaml
new file mode 100644
index 0000000..5f0db80
--- /dev/null
+++ b/src/test/resources/recursive/generics/with-children-as-set.yaml
@@ -0,0 +1,37 @@
+&id002 !!set
+? !!org.yaml.snakeyaml.recursive.generics.HumanGen
+ bankAccountOwner: &id001 !!org.yaml.snakeyaml.recursive.generics.HumanGen
+ bankAccountOwner: *id001
+ birthPlace: Leningrad
+ birthday: 1970-01-12T13:46:40Z
+ children: *id002
+ father: null
+ mother: null
+ name: Father
+ partner: &id003 !!org.yaml.snakeyaml.recursive.generics.HumanGen
+ bankAccountOwner: *id001
+ birthPlace: Saint-Petersburg
+ birthday: 1973-03-03T09:46:40Z
+ children: *id002
+ father: null
+ mother: null
+ name: Mother
+ partner: *id001
+ birthPlace: Munich
+ birthday: 1979-10-28T23:06:40Z
+ children: !!set {}
+ father: *id001
+ mother: *id003
+ name: Son
+ partner: null
+: null
+? !!org.yaml.snakeyaml.recursive.generics.HumanGen
+ bankAccountOwner: *id001
+ birthPlace: New York
+ birthday: 1983-04-24T02:40:00Z
+ children: !!set {}
+ father: *id001
+ mother: *id003
+ name: Daughter
+ partner: null
+: null
\ No newline at end of file
diff --git a/src/test/resources/recursive/generics/with-children.yaml b/src/test/resources/recursive/generics/with-children.yaml
new file mode 100644
index 0000000..fd3e976
--- /dev/null
+++ b/src/test/resources/recursive/generics/with-children.yaml
@@ -0,0 +1,36 @@
+&id002 !!org.yaml.snakeyaml.recursive.generics.HumanGen
+bankAccountOwner: &id001
+ bankAccountOwner: *id001
+ birthPlace: Leningrad
+ birthday: 1970-01-12T13:46:40Z
+ children: &id003 !!set
+ *id002: null
+ ? !!org.yaml.snakeyaml.recursive.generics.HumanGen
+ bankAccountOwner: *id001
+ birthPlace: New York
+ birthday: 1983-04-24T02:40:00Z
+ children: !!set {}
+ father: *id001
+ mother: &id004
+ bankAccountOwner: *id001
+ birthPlace: Saint-Petersburg
+ birthday: 1973-03-03T09:46:40Z
+ children: *id003
+ father: null
+ mother: null
+ name: Mother
+ partner: *id001
+ name: Daughter
+ partner: null
+ : null
+ father: null
+ mother: null
+ name: Father
+ partner: *id004
+birthPlace: Munich
+birthday: 1979-10-28T23:06:40Z
+children: !!set {}
+father: *id001
+mother: *id004
+name: Son
+partner: null
diff --git a/src/test/resources/recursive/no-children-1-pretty.yaml b/src/test/resources/recursive/no-children-1-pretty.yaml
new file mode 100644
index 0000000..5a6e4c3
--- /dev/null
+++ b/src/test/resources/recursive/no-children-1-pretty.yaml
@@ -0,0 +1,21 @@
+&id001 !!org.yaml.snakeyaml.recursive.Human {
+ bankAccountOwner: *id001,
+ birthPlace: Leningrad,
+ birthday: !!timestamp '1970-01-12T13:46:40Z',
+ children: !!set {
+ },
+ father: null,
+ mother: null,
+ name: Father,
+ partner: {
+ bankAccountOwner: *id001,
+ birthPlace: Saint-Petersburg,
+ birthday: !!timestamp '1973-03-03T09:46:40Z',
+ children: !!set {
+ },
+ father: null,
+ mother: null,
+ name: Mother,
+ partner: *id001
+ }
+}
diff --git a/src/test/resources/recursive/no-children-1.yaml b/src/test/resources/recursive/no-children-1.yaml
new file mode 100644
index 0000000..8f80490
--- /dev/null
+++ b/src/test/resources/recursive/no-children-1.yaml
@@ -0,0 +1,17 @@
+&id001 !!org.yaml.snakeyaml.recursive.Human
+bankAccountOwner: *id001
+birthPlace: Leningrad
+birthday: 1970-01-12T13:46:40Z
+children: !!set {}
+father: null
+mother: null
+name: Father
+partner:
+ bankAccountOwner: *id001
+ birthPlace: Saint-Petersburg
+ birthday: 1973-03-03T09:46:40Z
+ children: !!set {}
+ father: null
+ mother: null
+ name: Mother
+ partner: *id001
\ No newline at end of file
diff --git a/src/test/resources/recursive/with-children-2.yaml b/src/test/resources/recursive/with-children-2.yaml
new file mode 100644
index 0000000..e319e53
--- /dev/null
+++ b/src/test/resources/recursive/with-children-2.yaml
@@ -0,0 +1,35 @@
+&id002 !!org.yaml.snakeyaml.recursive.Human2
+bankAccountOwner: &id001
+ bankAccountOwner: *id001
+ birthPlace: Leningrad
+ birthday: 1970-01-12T13:46:40Z
+ children: &id003
+ *id002: son
+ ? bankAccountOwner: *id001
+ birthPlace: New York
+ birthday: 1983-04-24T02:40:00Z
+ children: {}
+ father: *id001
+ mother: &id004
+ bankAccountOwner: *id001
+ birthPlace: Saint-Petersburg
+ birthday: 1973-03-03T09:46:40Z
+ children: *id003
+ father: null
+ mother: null
+ name: Mother
+ partner: *id001
+ name: Daughter
+ partner: null
+ : daughter
+ father: null
+ mother: null
+ name: Father
+ partner: *id004
+birthPlace: Munich
+birthday: 1979-10-28T23:06:40Z
+children: {}
+father: *id001
+mother: *id004
+name: Son
+partner: null
diff --git a/src/test/resources/recursive/with-children-3.yaml b/src/test/resources/recursive/with-children-3.yaml
new file mode 100644
index 0000000..d3e0b37
--- /dev/null
+++ b/src/test/resources/recursive/with-children-3.yaml
@@ -0,0 +1,34 @@
+&id002 !!org.yaml.snakeyaml.recursive.Human3
+bankAccountOwner: &id001
+ bankAccountOwner: *id001
+ birthPlace: Leningrad
+ birthday: 1970-01-12T13:46:40Z
+ children: &id003
+ - *id002
+ - bankAccountOwner: *id001
+ birthPlace: New York
+ birthday: 1983-04-24T02:40:00Z
+ children: []
+ father: *id001
+ mother: &id004
+ bankAccountOwner: *id001
+ birthPlace: Saint-Petersburg
+ birthday: 1973-03-03T09:46:40Z
+ children: *id003
+ father: null
+ mother: null
+ name: Mother
+ partner: *id001
+ name: Daughter
+ partner: null
+ father: null
+ mother: null
+ name: Father
+ partner: *id004
+birthPlace: Munich
+birthday: 1979-10-28T23:06:40Z
+children: []
+father: *id001
+mother: *id004
+name: Son
+partner: null
diff --git a/src/test/resources/recursive/with-children-as-list.yaml b/src/test/resources/recursive/with-children-as-list.yaml
new file mode 100644
index 0000000..b7a1874
--- /dev/null
+++ b/src/test/resources/recursive/with-children-as-list.yaml
@@ -0,0 +1,35 @@
+&id002
+- !!org.yaml.snakeyaml.recursive.Human3
+ bankAccountOwner: &id001
+ bankAccountOwner: *id001
+ birthPlace: Leningrad
+ birthday: 1970-01-12T13:46:40Z
+ children: *id002
+ father: null
+ mother: null
+ name: Father
+ partner: &id003
+ bankAccountOwner: *id001
+ birthPlace: Saint-Petersburg
+ birthday: 1973-03-03T09:46:40Z
+ children: *id002
+ father: null
+ mother: null
+ name: Mother
+ partner: *id001
+ birthPlace: Munich
+ birthday: 1979-10-28T23:06:40Z
+ children: []
+ father: *id001
+ mother: *id003
+ name: Son
+ partner: null
+- !!org.yaml.snakeyaml.recursive.Human3
+ bankAccountOwner: *id001
+ birthPlace: New York
+ birthday: 1983-04-24T02:40:00Z
+ children: []
+ father: *id001
+ mother: *id003
+ name: Daughter
+ partner: null
diff --git a/src/test/resources/recursive/with-children-as-map.yaml b/src/test/resources/recursive/with-children-as-map.yaml
new file mode 100644
index 0000000..b09fc4a
--- /dev/null
+++ b/src/test/resources/recursive/with-children-as-map.yaml
@@ -0,0 +1,37 @@
+&id002 !!java.util.LinkedHashMap
+? !!org.yaml.snakeyaml.recursive.Human2
+ bankAccountOwner: &id001 !!org.yaml.snakeyaml.recursive.Human2
+ bankAccountOwner: *id001
+ birthPlace: Leningrad
+ birthday: 1970-01-12T13:46:40Z
+ children: *id002
+ father: null
+ mother: null
+ name: Father
+ partner: &id003 !!org.yaml.snakeyaml.recursive.Human2
+ bankAccountOwner: *id001
+ birthPlace: Saint-Petersburg
+ birthday: 1973-03-03T09:46:40Z
+ children: *id002
+ father: null
+ mother: null
+ name: Mother
+ partner: *id001
+ birthPlace: Munich
+ birthday: 1979-10-28T23:06:40Z
+ children: !!java.util.LinkedHashMap {}
+ father: *id001
+ mother: *id003
+ name: Son
+ partner: null
+: This is My Son
+? !!org.yaml.snakeyaml.recursive.Human2
+ bankAccountOwner: *id001
+ birthPlace: New York
+ birthday: 1983-04-24T02:40:00Z
+ children: !!java.util.LinkedHashMap {}
+ father: *id001
+ mother: *id003
+ name: Daughter
+ partner: null
+: This Is My Daughter
\ No newline at end of file
diff --git a/src/test/resources/recursive/with-children-as-set.yaml b/src/test/resources/recursive/with-children-as-set.yaml
new file mode 100644
index 0000000..00799f2
--- /dev/null
+++ b/src/test/resources/recursive/with-children-as-set.yaml
@@ -0,0 +1,37 @@
+&id002 !!set
+? !!org.yaml.snakeyaml.recursive.Human
+ bankAccountOwner: &id001 !!org.yaml.snakeyaml.recursive.Human
+ bankAccountOwner: *id001
+ birthPlace: Leningrad
+ birthday: 1970-01-12T13:46:40Z
+ children: *id002
+ father: null
+ mother: null
+ name: Father
+ partner: &id003 !!org.yaml.snakeyaml.recursive.Human
+ bankAccountOwner: *id001
+ birthPlace: Saint-Petersburg
+ birthday: 1973-03-03T09:46:40Z
+ children: *id002
+ father: null
+ mother: null
+ name: Mother
+ partner: *id001
+ birthPlace: Munich
+ birthday: 1979-10-28T23:06:40Z
+ children: !!java.util.LinkedHashSet {}
+ father: *id001
+ mother: *id003
+ name: Son
+ partner: null
+: null
+? !!org.yaml.snakeyaml.recursive.Human
+ bankAccountOwner: *id001
+ birthPlace: New York
+ birthday: 1983-04-24T02:40:00Z
+ children: !!java.util.LinkedHashSet {}
+ father: *id001
+ mother: *id003
+ name: Daughter
+ partner: null
+: null
\ No newline at end of file
diff --git a/src/test/resources/recursive/with-children-no-root-tag.yaml b/src/test/resources/recursive/with-children-no-root-tag.yaml
new file mode 100644
index 0000000..57aa0b3
--- /dev/null
+++ b/src/test/resources/recursive/with-children-no-root-tag.yaml
@@ -0,0 +1,35 @@
+&id002
+bankAccountOwner: &id001
+ bankAccountOwner: *id001
+ birthPlace: Leningrad
+ birthday: 1970-01-12T13:46:40Z
+ children: &id003 !!set
+ *id002: null
+ ? bankAccountOwner: *id001
+ birthPlace: New York
+ birthday: 1983-04-24T02:40:00Z
+ children: !!set {}
+ father: *id001
+ mother: &id004
+ bankAccountOwner: *id001
+ birthPlace: Saint-Petersburg
+ birthday: 1973-03-03T09:46:40Z
+ children: *id003
+ father: null
+ mother: null
+ name: Mother
+ partner: *id001
+ name: Daughter
+ partner: null
+ : null
+ father: null
+ mother: null
+ name: Father
+ partner: *id004
+birthPlace: Munich
+birthday: 1979-10-28T23:06:40Z
+children: !!set {}
+father: *id001
+mother: *id004
+name: Son
+partner: null
\ No newline at end of file
diff --git a/src/test/resources/recursive/with-children-pretty.yaml b/src/test/resources/recursive/with-children-pretty.yaml
new file mode 100644
index 0000000..5e77fe8
--- /dev/null
+++ b/src/test/resources/recursive/with-children-pretty.yaml
@@ -0,0 +1,43 @@
+&id002 !!org.yaml.snakeyaml.recursive.Human {
+ bankAccountOwner: &id001 {
+ bankAccountOwner: *id001,
+ birthPlace: Leningrad,
+ birthday: !!timestamp '1970-01-12T13:46:40Z',
+ children: &id003 !!set {
+ *id002: null,
+ ? {
+ bankAccountOwner: *id001,
+ birthPlace: New York,
+ birthday: !!timestamp '1983-04-24T02:40:00Z',
+ children: !!set {
+ },
+ father: *id001,
+ mother: &id004 {
+ bankAccountOwner: *id001,
+ birthPlace: Saint-Petersburg,
+ birthday: !!timestamp '1973-03-03T09:46:40Z',
+ children: *id003,
+ father: null,
+ mother: null,
+ name: Mother,
+ partner: *id001
+ },
+ name: Daughter,
+ partner: null
+ }
+ : null
+ },
+ father: null,
+ mother: null,
+ name: Father,
+ partner: *id004
+ },
+ birthPlace: Munich,
+ birthday: !!timestamp '1979-10-28T23:06:40Z',
+ children: !!set {
+ },
+ father: *id001,
+ mother: *id004,
+ name: Son,
+ partner: null
+}
diff --git a/src/test/resources/recursive/with-children.yaml b/src/test/resources/recursive/with-children.yaml
new file mode 100644
index 0000000..117bd28
--- /dev/null
+++ b/src/test/resources/recursive/with-children.yaml
@@ -0,0 +1,35 @@
+&id002
+bankAccountOwner: &id001
+ bankAccountOwner: *id001
+ birthPlace: Leningrad
+ birthday: 1970-01-12T13:46:40Z
+ children: &id003 !!set
+ *id002: null
+ ? bankAccountOwner: *id001
+ birthPlace: New York
+ birthday: 1983-04-24T02:40:00Z
+ children: !!set {}
+ father: *id001
+ mother: &id004
+ bankAccountOwner: *id001
+ birthPlace: Saint-Petersburg
+ birthday: 1973-03-03T09:46:40Z
+ children: *id003
+ father: null
+ mother: null
+ name: Mother
+ partner: *id001
+ name: Daughter
+ partner: null
+ : null
+ father: null
+ mother: null
+ name: Father
+ partner: *id004
+birthPlace: Munich
+birthday: 1979-10-28T23:06:40Z
+children: !!set {}
+father: *id001
+mother: *id004
+name: Son
+partner: null
diff --git a/src/test/resources/recursive/with-childrenArray-no-root-tag.yaml b/src/test/resources/recursive/with-childrenArray-no-root-tag.yaml
new file mode 100644
index 0000000..c76437b
--- /dev/null
+++ b/src/test/resources/recursive/with-childrenArray-no-root-tag.yaml
@@ -0,0 +1,34 @@
+&id002
+bankAccountOwner: &id001
+ bankAccountOwner: *id001
+ birthPlace: Leningrad
+ birthday: 1970-01-12T13:46:40Z
+ children: &id003
+ - *id002
+ - bankAccountOwner: *id001
+ birthPlace: New York
+ birthday: 1983-04-24T02:40:00Z
+ children: []
+ father: *id001
+ mother: &id004
+ bankAccountOwner: *id001
+ birthPlace: Saint-Petersburg
+ birthday: 1973-03-03T09:46:40Z
+ children: *id003
+ father: null
+ mother: null
+ name: Mother
+ partner: *id001
+ name: Daughter
+ partner: null
+ father: null
+ mother: null
+ name: Father
+ partner: *id004
+birthPlace: Munich
+birthday: 1979-10-28T23:06:40Z
+children: []
+father: *id001
+mother: *id004
+name: Son
+partner: null
\ No newline at end of file
diff --git a/src/test/resources/recursive/with-childrenArray.yaml b/src/test/resources/recursive/with-childrenArray.yaml
new file mode 100644
index 0000000..b174b7b
--- /dev/null
+++ b/src/test/resources/recursive/with-childrenArray.yaml
@@ -0,0 +1,34 @@
+&id002 !!org.yaml.snakeyaml.recursive.Human_WithArrayOfChildrenTest$Human_WithArrayOfChildren
+bankAccountOwner: &id001
+ bankAccountOwner: *id001
+ birthPlace: Leningrad
+ birthday: 1970-01-12T13:46:40Z
+ children: &id003
+ - *id002
+ - bankAccountOwner: *id001
+ birthPlace: New York
+ birthday: 1983-04-24T02:40:00Z
+ children: []
+ father: *id001
+ mother: &id004
+ bankAccountOwner: *id001
+ birthPlace: Saint-Petersburg
+ birthday: 1973-03-03T09:46:40Z
+ children: *id003
+ father: null
+ mother: null
+ name: Mother
+ partner: *id001
+ name: Daughter
+ partner: null
+ father: null
+ mother: null
+ name: Father
+ partner: *id004
+birthPlace: Munich
+birthday: 1979-10-28T23:06:40Z
+children: []
+father: *id001
+mother: *id004
+name: Son
+partner: null
\ No newline at end of file
diff --git a/src/test/resources/representer/scalar-style1.yaml b/src/test/resources/representer/scalar-style1.yaml
new file mode 100644
index 0000000..a1c6842
--- /dev/null
+++ b/src/test/resources/representer/scalar-style1.yaml
@@ -0,0 +1,6 @@
+name: Steve Jobs
+address: |-
+ Name
+ Street Number
+ Country
+description: 1111111111 2222222222 3333333333 4444444444 5555555555 6666666666 7777777777 8888888888 9999999999 0000000000
diff --git a/src/test/resources/representer/scalar-style2.yaml b/src/test/resources/representer/scalar-style2.yaml
new file mode 100644
index 0000000..cbbc13d
--- /dev/null
+++ b/src/test/resources/representer/scalar-style2.yaml
@@ -0,0 +1,10 @@
+name: Steve Jobs
+address: |-
+ Name
+ Street Number
+ Country
+description: >-
+ 1111111111 2222222222 3333333333
+ 4444444444 5555555555 6666666666
+ 7777777777 8888888888 9999999999
+ 0000000000
diff --git a/src/test/resources/representer/scalar-style3.yaml b/src/test/resources/representer/scalar-style3.yaml
new file mode 100644
index 0000000..8402790
--- /dev/null
+++ b/src/test/resources/representer/scalar-style3.yaml
@@ -0,0 +1,7 @@
+name: Steve Jobs
+address: |-
+ Name
+ Street Number
+ Country
+description: >-
+ 1111111111 2222222222 3333333333 4444444444 5555555555 6666666666 7777777777 8888888888 9999999999 0000000000
diff --git a/src/test/resources/representer/stacktrace1.txt b/src/test/resources/representer/stacktrace1.txt
new file mode 100644
index 0000000..d03a10d
--- /dev/null
+++ b/src/test/resources/representer/stacktrace1.txt
@@ -0,0 +1,6 @@
+Exception in thread "main" org.apache.commons.lang.UnhandledException: org.apache.commons.lang.UnhandledException: while parsing a block mapping
+ at org.yaml.snakeyaml.parser.ParserImpl$ParseBlockMappingKey.produce(ParserImpl.java:575)
+ at org.yaml.snakeyaml.parser.ParserImpl.peekEvent(ParserImpl.java:162)
+ at org.yaml.snakeyaml.parser.ParserImpl.checkEvent(ParserImpl.java:147)
+ at org.yaml.snakeyaml.composer.Composer.composeMappingNode(Composer.java:227)
+ at org.yaml.snakeyaml.composer.Composer.composeNode(Composer.java:159)
diff --git a/src/test/resources/representer/stacktrace1.yaml b/src/test/resources/representer/stacktrace1.yaml
new file mode 100644
index 0000000..9d21a75
--- /dev/null
+++ b/src/test/resources/representer/stacktrace1.yaml
@@ -0,0 +1,8 @@
+|
+ Exception in thread "main" org.apache.commons.lang.UnhandledException: org.apache.commons.lang.UnhandledException: while parsing a block mapping
+ at org.yaml.snakeyaml.parser.ParserImpl$ParseBlockMappingKey.produce(ParserImpl.java:575)
+ at org.yaml.snakeyaml.parser.ParserImpl.peekEvent(ParserImpl.java:162)
+ at org.yaml.snakeyaml.parser.ParserImpl.checkEvent(ParserImpl.java:147)
+ at org.yaml.snakeyaml.composer.Composer.composeMappingNode(Composer.java:227)
+ at org.yaml.snakeyaml.composer.Composer.composeNode(Composer.java:159)
+
diff --git a/src/test/resources/representer/stacktrace2.txt b/src/test/resources/representer/stacktrace2.txt
new file mode 100644
index 0000000..8e6736a
--- /dev/null
+++ b/src/test/resources/representer/stacktrace2.txt
@@ -0,0 +1,6 @@
+org.apache.commons.lang.UnhandledException@ while parsing a block mapping
+ at org.yaml.snakeyaml.parser.ParserImpl$ParseBlockMappingKey.produce(ParserImpl.java@575)
+ at org.yaml.snakeyaml.parser.ParserImpl.peekEvent(ParserImpl.java@162)
+ at org.yaml.snakeyaml.parser.ParserImpl.checkEvent(ParserImpl.java@147)
+ at org.yaml.snakeyaml.composer.Composer.composeMappingNode(Composer.java@227)
+ at org.yaml.snakeyaml.composer.Composer.composeNode(Composer.java@159)
diff --git a/src/test/resources/representer/stacktrace3.txt b/src/test/resources/representer/stacktrace3.txt
new file mode 100644
index 0000000..e9a8f21
--- /dev/null
+++ b/src/test/resources/representer/stacktrace3.txt
@@ -0,0 +1,6 @@
+org.apache.commons.lang.UnhandledException@ while parsing a block mapping
+ at org.yaml.snakeyaml.parser.ParserImpl$ParseBlockMappingKey.produce(ParserImpl.java@575)
+ at org.yaml.snakeyaml.parser.ParserImpl.peekEvent(ParserImpl.java@162)
+ at org.yaml.snakeyaml.parser.ParserImpl.checkEvent(ParserImpl.java@147)
+ at org.yaml.snakeyaml.composer.Composer.composeMappingNode(Composer.java@227)
+ at org.yaml.snakeyaml.composer.Composer.composeNode(Composer.java@159)
diff --git a/src/test/resources/ruby/ruby1.yaml b/src/test/resources/ruby/ruby1.yaml
new file mode 100644
index 0000000..e1329ec
--- /dev/null
+++ b/src/test/resources/ruby/ruby1.yaml
@@ -0,0 +1,10 @@
+--- !ruby/object:Test::Module::Object
+ sub1: !ruby/object:Test::Module::Sub1
+ att1: []
+ att2: 0
+ att3: []
+ sub2: !ruby/object:Test::Module::Sub2
+ att1: MyString
+ att2:
+ - entry1
+ att3: 12345
diff --git a/src/test/resources/specification/example2_1.yaml b/src/test/resources/specification/example2_1.yaml
new file mode 100644
index 0000000..d12e671
--- /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 0000000..61808f6
--- /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 0000000..9123ce2
--- /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 0000000..1fc33f9
--- /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 0000000..13fb656
--- /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 0000000..59943de
--- /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 0000000..80b89a6
--- /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_15_dumped.yaml b/src/test/resources/specification/example2_15_dumped.yaml
new file mode 100644
index 0000000..cc2d963
--- /dev/null
+++ b/src/test/resources/specification/example2_15_dumped.yaml
@@ -0,0 +1,7 @@
+>
+ Sammy Sosa completed another fine season with great stats.
+
+ 63 Home Runs
+ 0.288 Batting Average
+
+ What a year!
\ No newline at end of file
diff --git a/src/test/resources/specification/example2_16.yaml b/src/test/resources/specification/example2_16.yaml
new file mode 100644
index 0000000..9f66d88
--- /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 0000000..3e899c0
--- /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 0000000..59398a6
--- /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 0000000..7ddff26
--- /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 0000000..bedc4a5
--- /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 0000000..c3fe6aa
--- /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 0000000..9d82173
--- /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 0000000..2b378bd
--- /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 0000000..e0a8bfa
--- /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 0000000..8aeb1a4
--- /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 0000000..7b7ec94
--- /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 0000000..60bfc06
--- /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 0000000..c065b2a
--- /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 0000000..aaac185
--- /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 0000000..adbe4e6
--- /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 0000000..03cc760
--- /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 0000000..2e95415
--- /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 0000000..b87063e
--- /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 0000000..1180757
--- /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 0000000..1742cd2
--- /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 0000000..769ac31
--- /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 0000000..3143763
--- /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 0000000..395e79c
--- /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 0000000..51a89b8
--- /dev/null
+++ b/src/test/resources/specification/example2_27_dumped.yaml
@@ -0,0 +1,20 @@
+!!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:
+- {description: Basketball, price: 450.0, quantity: 4, sku: BL394D}
+- {description: Super Hoop, price: 2392.0, quantity: 1, sku: BL4438H}
+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 0000000..eb5fb8a
--- /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 0000000..2c884b7
--- /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 0000000..430f6b3
--- /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 0000000..cdd7770
--- /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 0000000..7a957b2
--- /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 0000000..bc711d5
--- /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 0000000..05e102d
--- /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 0000000..e264180
--- /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 0000000..022446d
--- /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 0000000..a5d35b0
--- /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 0000000..ee4a48f
--- /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 0000000..4fa0f45
--- /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 0000000..05f55b9
--- /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 0000000..5849115
--- /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 0000000..e05dc88
--- /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 0000000..81c5d51
--- /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 0000000..3eb7919
--- /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
diff --git a/src/test/resources/template/etalon1.yaml b/src/test/resources/template/etalon1.yaml
new file mode 100644
index 0000000..21e45a9
--- /dev/null
+++ b/src/test/resources/template/etalon1.yaml
@@ -0,0 +1,9 @@
+empty: []
+id: id123
+list:
+- aaa
+- bbb
+- ccc
+point:
+ x: 1.0
+ y: 2.0
\ No newline at end of file
diff --git a/src/test/resources/template/etalon2-template.yaml b/src/test/resources/template/etalon2-template.yaml
new file mode 100644
index 0000000..979892f
--- /dev/null
+++ b/src/test/resources/template/etalon2-template.yaml
@@ -0,0 +1,9 @@
+%YAML 1.1
+---
+#Welcome to my Beans !!!
+id: id123 # the ID must be first
+point: [1.0, 2.0]
+#collection are at the end
+list: [aaa, bbb, ccc]
+
+#empty collection is not emitted
diff --git a/src/test/resources/template/mybean1.vm b/src/test/resources/template/mybean1.vm
new file mode 100644
index 0000000..a4c2804
--- /dev/null
+++ b/src/test/resources/template/mybean1.vm
@@ -0,0 +1,12 @@
+%YAML 1.1
+---
+#Welcome to my Beans !!!
+id: $bean.id # the ID must be first
+point: [$bean.point.x, $bean.point.y]
+#collection are at the end
+list: $list
+#foreach( $item in $bean.empty )
+ - $item
+#end
+#empty collection is not emitted
+