diff options
author | somov <none@none> | 2009-03-14 13:25:40 +0100 |
---|---|---|
committer | somov <none@none> | 2009-03-14 13:25:40 +0100 |
commit | 159b07eeff6fdb7f32702b6243e827109455aecc (patch) | |
tree | 30fc25c989dd9ccc37ddad111241aad848460d3e | |
download | snakeyaml-159b07eeff6fdb7f32702b6243e827109455aecc.tar.gz |
update wiki for JavaBeanParser
676 files changed, 23440 insertions, 0 deletions
diff --git a/.classpath b/.classpath new file mode 100644 index 00000000..7e665fe5 --- /dev/null +++ b/.classpath @@ -0,0 +1,10 @@ +<classpath>
+ <classpathentry kind="src" path="src/main/java"/>
+ <classpathentry kind="src" path="src/test/java"/>
+ <classpathentry kind="src" path="src/test/resources" excluding="**/*.java"/>
+ <classpathentry kind="output" path="bin"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="var" path="M2_REPO/commons-logging/commons-logging/1.1.1/commons-logging-1.1.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/junit/junit/3.8.2/junit-3.8.2.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/springframework/spring/2.5.6/spring-2.5.6.jar"/>
+</classpath>
\ No newline at end of file diff --git a/.hgignore b/.hgignore new file mode 100644 index 00000000..7d6abe2e --- /dev/null +++ b/.hgignore @@ -0,0 +1,5 @@ + +syntax: regexp +^target$ +^bin$ +^\.settings$ diff --git a/.hgtags b/.hgtags new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/.hgtags diff --git a/.project b/.project new file mode 100644 index 00000000..c975a15e --- /dev/null +++ b/.project @@ -0,0 +1,13 @@ +<projectDescription>
+ <name>SnakeYAML</name>
+ <comment>YAML 1.1 parser and emitter for Java</comment>
+ <projects/>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
\ No newline at end of file diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 00000000..db6435d1 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,21 @@ +SnakeYAML was created in late 2008 with an intention +to implement a reference YAML parser for Java. + +The PRIMARY AUTHORS are (and/or have been): + +* Andrey Somov <py4fun@gmail.com> + +And here is an inevitably incomplete list of MUCH-APPRECIATED CONTRIBUTORS -- +people who have submitted patches, reported bugs, helped +answer newbie questions, and generally made SnakeYAML that much better: + +Kirill Simonov <xi@resolvent.net> - writing the original Python code. +Ola Bini <ola@ologix.com> +kirkz at sourceforge +tailwaggers at sourceforge +jberry at sourceforge +jscheid37 at sourceforge +Red Forks at gmail +Nathan Sweet +James Nissel +Christophe Desguez diff --git a/Eclipse-format.xml b/Eclipse-format.xml new file mode 100644 index 00000000..9717b7da --- /dev/null +++ b/Eclipse-format.xml @@ -0,0 +1,264 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<profiles version="11">
+<profile kind="CodeFormatterProfile" name="SnakeYAML" version="11">
+<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="0"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression" value="80"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_binary_operator" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="2"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_binary_operator" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="0"/>
+<setting id="org.eclipse.jdt.core.compiler.source" value="1.5"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.format_line_comments" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.align_type_members_on_columns" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="100"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration" value="0"/>
+<setting id="org.eclipse.jdt.core.formatter.indentation.size" value="4"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_assignment" value="0"/>
+<setting id="org.eclipse.jdt.core.compiler.problem.assertIdentifier" value="error"/>
+<setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="space"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.compiler.problem.enumIdentifier" value="error"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="4"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_empty_lines" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression" value="16"/>
+<setting id="org.eclipse.jdt.core.compiler.compliance" value="1.5"/>
+<setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_binary_expression" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.format_javadoc_comments" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="80"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_import_groups" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="0"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.wrap_before_binary_operator" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.format_html" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.format_source_code" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="insert"/>
+<setting id="org.eclipse.jdt.core.compiler.codegen.targetPlatform" value="1.5"/>
+<setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="0"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line" value="false"/>
+</profile>
+</profiles>
diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..f52fb68c --- /dev/null +++ b/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2008 + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. @@ -0,0 +1,233 @@ += SnakeYAML = + +'''SnakeYAML is a YAML parser and emitter for Java.''' + + +== Overview == + +[http://yaml.org/ YAML] is a data serialization format designed for human +readability and interaction with scripting languages. + +[http://pyyaml.org/wiki/SnakeYAML SnakeYAML] is a YAML parser and emitter for +the Java programming language. SnakeYAML tries to be as close as possible to PyYAML +API allowing documents to be easily exchanged between Python and Java. + +SnakeYAML features + + * a '''complete''' [http://yaml.org/spec/current.html YAML 1.1] parser. + In particular, SnakeYAML can parse all examples from the specification. + * Unicode support including UTF-8/UTF-16 input/output. + * high-level API for serializing and deserializing native Java objects. + * support for all types from the [http://yaml.org/type/index.html YAML types repository]. + * relatively sensible error messages. + +Note that SnakeYAML is still young and may have some bugs. + +== Requirements == + +SnakeYAML requires Java 5 or higher. + + +== Download and Installation == + +The current stable release of SnakeYAML: '''1.1'''. + +Download links: + + * '''source''': http://www.assembla.com/spaces/snakeyaml/trac_mercurial_tool + * '''JAR package''': http://snakeyamlrepo.appspot.com/repository/SnakeYAML/SnakeYAML/1.1/SnakeYAML-1.1.jar + * '''ZIP archive''': http://www.assembla.com/spaces/snakeyaml/documents/bK10C2_Aur3AHfeJe5afGb/download?filename=SnakeYAML-all-1.1.zip + * '''Repository''': http://snakeyamlrepo.appspot.com/ + +Browse 1.1 reports: + + * '''Maven generated report''': http://snakeyamlrepo.appspot.com/releases/1.1/site/index.html + * '''Project's report''': http://snakeyamlrepo.appspot.com/releases/1.1/site/project-reports.html + * '''Javadocs''': http://snakeyamlrepo.appspot.com/releases/1.1/site/apidocs/index.html + * '''Changes report''': http://snakeyamlrepo.appspot.com/releases/1.1/site/changes-report.html + * '''Maven generated report''': http://snakeyamlrepo.appspot.com/releases/1.1/site/index.html + * '''Test coverage report''': http://snakeyamlrepo.appspot.com/releases/1.1/site/cobertura/index.html + +Maven 2 configuration: + +Repository definition (in settings.xml) +{{{ +<repositories> + ... + <repository> + <id>snakeyaml</id> + <name>SnakeYAML repository</name> + <url>http://snakeyamlrepo.appspot.com/repository</url> + </repository> + ... +</repositories> +}}} + +Dependency definition (in pom.xml) +{{{ +<dependencies> + ... + <dependency> + <groupId>SnakeYAML</groupId> + <artifactId>SnakeYAML</artifactId> + <version>1.1</version> + </dependency> + ... +</dependencies> +}}} + +== Documentation == + +''Loading:'' +{{{ +Yaml yaml = new Yaml(); +Object obj = yaml.load("a: 1\nb: 2\nc:\n - aaa\n - bbb"); +System.out.println(obj); + +{b=2, c=[aaa, bbb], a=1} +}}} +''Dumping:'' +{{{ + +Map<String, String> map = new HashMap<String, String>(); +map.put("name", "Pushkin"); +Yaml yaml = new Yaml(); +String output = yaml.dump(map); +System.out.println(output); + +--- +name: Pushkin +}}} + +For more details, please check [wiki:Documentation SnakeYAML Documentation]. + + +== History == +'''1.1 (2009-03-14)''' + * test coverage reached 98% + * byte[] is used for type `binary` + * Better Spring support: the root `JavaBean` class can be specified as a String + * Performance: fix a bug with expanding Regular Expressions (thanks to Christophe Desguez) + * Fix ticket #4: java.sql.Date was not handled properly (thanks to Christophe Desguez) + * Introduce `Enums` in `DumperOptions` + * minor refactoring and bug fixes + * add [/snakeyaml/wiki/Documentation#Threading Threads] and + [/snakeyaml/wiki/Documentation#Spring Spring] sections to the wiki documentation + +'''1.0.1 (2009-02-18)''' + * proper `Enum` [http://trac-hg.assembla.com/snakeyaml/wiki/Documentation#Enum support] (thanks to James Nissel) + * minor performance improvement + * fix minor issues in `DumperOptions` + +'''1.0 (2009-02-06)''' + * Use `LinkedHashMap` to respect the order where it is required (`ScannerImpl`.java and Emitter.java) + * The mailing list is renamed to `snakeyaml-core` to avoid a name conflict in `Google` `AppEngine` + +'''1.0rc2 (2009-01-22)''' + * add [http://trac-hg.assembla.com/snakeyaml/wiki/Documentation#JavaBeans JavaBeans section] to the wiki + * Provide possibility to define/eliminate the root tag for `JavaBeans` + * Arrays as `JavaBens` properties are properly supported + * Do not emit redundant tags for `JavaBeans` + * Respect public fields in `JavaBeans` + +'''1.0rc1 (2009-01-16)''' + * Implement [http://trac-hg.assembla.com/snakeyaml/wiki/Documentation#Typesafecollections type safe List and Map] + as a property of a custom Java class + * remove Java 6 dependencies + +'''0.91 (2009-01-14)''' + * Support [http://trac-hg.assembla.com/snakeyaml/wiki/Documentation#Shortcuts shortcut tags] for custom classes + * Import canonical scanner and parser from PyYAML + +'''0.9 (2009-01-12)''' + * Minor changes + * Add possibility [http://trac-hg.assembla.com/snakeyaml/wiki/Documentation#Providingthetopleveltype to provide] the top level type + * Fix a bug in Emitter when writing folded scalars + +'''0.8 (2009-01-07)''' + * Add possibility to use java.io.Reader as input + * import changes from [http://pyyaml.org/wiki/PyYAML#History PyYAML 3.07/3.08] + * Use global tags (with !!) to load/dump Java custom classes + * Fix parsing Long.MIN_VALUE + * when constructing integers try to create the first in the following order: + Integer -> Long -> `BigInteger` + +'''0.7 (2008-12-20)''' + * improve test coverage + +'''0.6 (2008-12-17)''' + * add more examples to the documentation + * Public interface is using Iterator instead of Iterable + * Sort names when `JavaBeans` are represented + * defaultFlowStyle for Dumper is configurable in `DumperOptions` + +'''0.5 (2008-12-12)''' + * Add possibility to define an implicit resolver + * Add possibility to define an explicit constructor + * Java objects can be constructed from mapping (javabean), from sequence (constructor), + from scalar (constructor) + * fix omap and pairs tags + * Implement possibility to define a custom List or Map implementation + * Implement possibility to define a custom Representer + * Support arrays of reference types + * Import latest changes from PyYAML (after 3.06 was released) + * Fix Node identity to avoid aliases for simple types - [1, 1] + * Recursive objects can be represented (but not yet constructed) + * Binary is represented back as String + * Fix: 'null' can be a key in a map + * Fix: 'set' type works + +'''0.4 (2008-11-11)''' + * Fix a deviation with PyYAML in method scanBlockScalar(). + Fix a bug in [https://jvyaml.dev.java.net/ JvYaml] that the trailing '\n' in a + block scalar was removed + * Restore from PyYAML the way the keys are parsed. (Restored methods are + stalePossibleSimpleKeys() and removePossibleSimpleKey().) + Fix issue http://code.google.com/p/jvyamlb/issues/detail?id=6 + * Change public interface. Rename YAML to Yaml. Remove all static methods from Yaml. + Factory and configuration must be injected at the constructor. + Yaml loadAll() and dumpAll() methods work with Iterable instead of List. + This way is closer to PyYAML API + * Reader as in PyYAML is implemented. BOM is properly supported. Fix a known [http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058 bug] in Java + * Fix issue: https://jvyaml.dev.java.net/issues/show_bug.cgi?id=11 + * Respect Unicode characters. + Fix issue: https://jvyaml.dev.java.net/issues/show_bug.cgi?id=10 + * Respect sign for float. + Fix issue: https://jvyaml.dev.java.net/issues/show_bug.cgi?id=13 + * Binary data is represented as [http://java.sun.com/javase/6/docs/api/java/nio/ByteBuffer.html ByteBuffer] + * When parsed, a timestamp in the canonical form (i.e, 2001-12-15T02:59:43.1Z) is + interpreted as if it is in the default time zone. + Fix issue: https://jvyaml.dev.java.net/issues/show_bug.cgi?id=7 + * Restore Mark from PyYAML to show a snippet of YAML in case of invalid data + * Reformat the source files and provide formatter for Eclipse + * Mavenize the project and apply Maven standard folder structure + * Import [https://jvyaml.dev.java.net JvYaml] source from CVS to Mercurial + +== Development and bug reports == + +You may check out the SnakeYAML source code from +[http://hg.assembla.com/snakeyaml SnakeYAML Mercurial repository]. + +You may also +[http://trac-hg.assembla.com/snakeyaml/browser browse] the SnakeYAML source code. + +If you find a bug in SnakeYAML, please +[http://trac-hg.assembla.com/snakeyaml/newticket file a bug report]. +You may review open bugs through +[http://trac-hg.assembla.com/snakeyaml/report/1 the list of open tickets]. + +You may discuss SnakeYAML at +[http://groups.google.com/group/snakeyaml-core the mailing list]. + +== TODO == + * proper `enum` support + +== Known bugs == + * Recursive objects are not fully supported. Dumping works but loading does not. + +== Author and copyright == + +The SnakeYAML is developed by Andrey Somov and it is based on [http://pyyaml.org/wiki/PyYAML PyYAML] +module written by [mailto:xi@resolvent.net Kirill Simonov]. + +SnakeYAML is released under the MIT license. diff --git a/announcement.msg b/announcement.msg new file mode 100644 index 00000000..39d77a49 --- /dev/null +++ b/announcement.msg @@ -0,0 +1,58 @@ +From: Andrey Somov <py4fun@gmail.com> +To: yaml-core@lists.sourceforge.net +Subject: [ANN] SnakeYAML-1.1: improve performance and test coverage + +============================= + Announcing SnakeYAML-1.1 +============================= + +A new release of SnakeYAML is now available: + + http://trac-hg.assembla.com/snakeyaml/ + +This release delivers a significant performance improvements as well as minor changes +and bug fixes. + +Changes +======= + * test coverage reached 98% + * Better Spring support: the root JavaBean class to parse can be specified as a String + * Performance: fix a bug with expanding Regular Expressions + * Fix ticket #4: java.sql.Date was not handled properly + * Introduce Enums in DumperOptions + * minor bug fixes + +Resources +========= + +SnakeYAML homepage: http://trac-hg.assembla.com/snakeyaml/ +SnakeYAML documentation: http://trac-hg.assembla.com/snakeyaml/wiki/Documentation + +JAR package: http://snakeyamlrepo.appspot.com/repository/SnakeYAML/SnakeYAML/1.1/SnakeYAML-1.1.jar +Reports: http://snakeyamlrepo.appspot.com/ + +SnakeYAML Mercurial repository: http://hg.assembla.com/snakeyaml +Submit a bug report: http://trac-hg.assembla.com/snakeyaml/newticket + +YAML homepage: http://yaml.org/ +YAML-core mailing list: http://lists.sourceforge.net/lists/listinfo/yaml-core + + +About SnakeYAML +============ + +YAML is a data serialization format designed for human readability and +interaction with scripting languages. SnakeYAML is a YAML parser and +emitter for Java. + +SnakeYAML features a complete YAML 1.1 parser. +SnakeYAML is applicable for a broad range of tasks from complex +configuration files to object serialization and persistence. + + +Copyright +========= + +SnakeYAML is developed by Andrey Somov <py4fun@gmail.com>. + +SnakeYAML is released under the MIT license. diff --git a/doc/wiki/Documentation.txt b/doc/wiki/Documentation.txt new file mode 100644 index 00000000..93de3702 --- /dev/null +++ b/doc/wiki/Documentation.txt @@ -0,0 +1,1335 @@ += SnakeYAML Documentation =
+
+''This documentation is very brief and incomplete. Feel free to fix or improve it.''
+
+
+[[PageOutline]]
+
+
+== Installation ==
+
+Download the source package and put it to the classpath.
+
+Note that there are some subtle (but not really significant) differences between [http://pyyaml.org/wiki/PyYAML Python] and [http://trac-hg.assembla.com/snakeyaml/wiki SnakeYaml] parsers
+and emitters.
+
+== Frequently Asked Questions ==
+
+=== Dictionaries without nested collections are not dumped correctly ===
+
+''Why does''
+{{{
+Yaml yaml = new Yaml();
+String document = " a: 1\n b:\n c: 3\n d: 4\n";
+System.out.println(document);
+System.out.println(yaml.dump(yaml.load(document)));
+}}}
+''give''
+{{{
+ a: 1
+ b:
+ c: 3
+ d: 4
+
+a: 1
+b: {c: 3, d: 4}
+}}}
+
+It's a correct output despite the fact that the style of the nested mapping is different.
+
+By default, SnakeYAML chooses the style of a collection depending on whether it has nested
+collections. If a collection has nested collections, it will be assigned the block style.
+Otherwise it will have the flow style.
+
+If you want collections to be always serialized in the block style, set the parameter
+'''`defaultFlowStyle`''' of '''`DumperOptions`''' to '''`block`'''. For instance,
+{{{
+DumperOptions options = new DumperOptions();
+options.setDefaultFlowStyle(DumperOptions.DefaultFlowStyle.BLOCK);
+Yaml yaml = new Yaml(options);
+String document = " a: 1\n b:\n c: 3\n d: 4\n";
+System.out.println(yaml.dump(yaml.load(document)));
+
+a: 1
+b:
+ c: 3
+ d: 4
+}}}
+
+You can find an example [http://trac-hg.assembla.com/snakeyaml/browser/src/test/java/examples/CollectionStyleTest.java here]
+
+=== Binary Data ===
+`byte[]` is represented as binary. Also when a `String` contains at least one non-printable character the
+`!!binary` type is emitted.
+
+Binary scalar is parsed as `byte[]`.
+
+An example can found [http://trac-hg.assembla.com/snakeyaml/browser/src/test/java/org/yaml/snakeyaml/types/BinaryTagTest.java here].
+
+== Tutorial ==
+
+Start with instantiating the '''`org.yaml.snakeyaml.Yaml`''' instance.
+
+{{{
+Yaml yaml = new Yaml();
+}}}
+
+
+=== Loading YAML ===
+
+The method '''`Yaml.load()`''' converts a YAML document to a Java object.
+
+{{{
+Yaml yaml = new Yaml();
+String document = "\n- Hesperiidae\n- Papilionidae\n- Apatelodidae\n- Epiplemidae";
+List<String> list = (List<String>) yaml.load(document);
+System.out.println(list);
+
+['Hesperiidae', 'Papilionidae', 'Apatelodidae', 'Epiplemidae']
+}}}
+You can find an example [http://trac-hg.assembla.com/snakeyaml/browser/src/test/java/examples/LoadExampleTest.java here]
+
+'''`Yaml.load()`''' accepts a String or
+an `InputStream` object. '''`Yaml.load(InputStream stream)`''' detects the encoding
+by checking the '''BOM''' (byte order mark) sequence at the beginning of the
+stream. If no '''BOM''' is present, the '''utf-8''' encoding is assumed.
+
+'''`Yaml.load()`''' returns a Java object.
+
+{{{
+public void testLoadFromString() {
+ Yaml yaml = new Yaml();
+ String document = "hello: 25";
+ Map map = (Map) yaml.load(document);
+ assertEquals("{hello=25}", map.toString());
+ assertEquals(new Long(25), map.get("hello"));
+}
+
+public void testLoadFromStream() throws FileNotFoundException {
+ InputStream input = new FileInputStream(new File("src/test/resources/reader/utf-8.txt"));
+ Yaml yaml = new Yaml();
+ Object data = yaml.load(input);
+ assertEquals("test", data);
+ //
+ data = yaml.load(new ByteArrayInputStream("test2".getBytes()));
+ assertEquals("test2", data);
+}
+}}}
+
+If a String or a stream contains several documents, you may load them all with the
+'''`Yaml.loadAll()`''' method.
+{{{
+---
+Time: 2001-11-23 15:01:42 -5
+User: ed
+Warning:
+ This is an error message
+ for the log file
+---
+Time: 2001-11-23 15:02:31 -5
+User: ed
+Warning:
+ A slightly different error
+ message.
+---
+Date: 2001-11-23 15:03:17 -5
+User: ed
+Fatal:
+ Unknown variable "bar"
+Stack:
+ - file: TopClass.py
+ line: 23
+ code: |
+ x = MoreObject("345\n")
+ - file: MoreClass.py
+ line: 58
+ code: |-
+ foo = bar
+}}}
+{{{
+public void testLoadManyDocuments() throws FileNotFoundException {
+ InputStream input = new FileInputStream(new File(
+ "src/test/resources/specification/example2_28.yaml"));
+ Yaml yaml = new Yaml();
+ int counter = 0;
+ for (Object data : yaml.loadAll(input)) {
+ System.out.println(data);
+ counter++;
+ }
+ assertEquals(3, counter);
+}
+}}}
+{{{
+{Time=Fri Nov 23 21:01:42 CET 2001, User=ed, Warning=This is an error message for the log file}
+{Time=Fri Nov 23 21:02:31 CET 2001, User=ed, Warning=A slightly different error message.}
+{Date=Fri Nov 23 21:03:17 CET 2001, User=ed, Fatal=Unknown variable "bar", Stack=[{file=TopClass.py, line=23, code=x = MoreObject("345\n")
+}, {file=MoreClass.py, line=58, code=foo = bar}]}
+}}}
+
+SnakeYAML allows you [http://trac-hg.assembla.com/snakeyaml/browser/src/test/java/examples/AnyObjectExampleTest.java to construct] a Java object of any type.
+
+{{{
+none: [~, null]
+bool: [true, false, on, off]
+int: 42
+float: 3.14159
+list: [LITE, RES_ACID, SUS_DEXT]
+dict: {hp: 13, sp: 5}
+}}}
+
+{{{
+public void testLoad() throws IOException {
+ String doc = Util.getLocalResource("examples/any-object-example.yaml");
+ Yaml yaml = new Yaml();
+ Map<String, Object> object = (Map<String, Object>) yaml.load(doc);
+ System.out.println(object);
+}
+}}}
+{{{
+{none=[null, null], bool=[true, false, true, false], int=42, float=3.14159,
+list=[LITE, RES_ACID, SUS_DEXT], dict={hp=13, sp=5}}
+}}}
+
+Even instances of custom Java classes [http://trac-hg.assembla.com/snakeyaml/browser/src/test/java/org/yaml/snakeyaml/constructor/ConstructorTest.java can be constructed].
+{{{
+/**
+ * create JavaBean
+ */
+public void testGetBeanAssumeClass() {
+ String data = "--- !org.yaml.snakeyaml.constructor.Person\nfirstName: Andrey\nage: 99";
+ Object obj = construct(data);
+ assertNotNull(obj);
+ assertTrue("Unexpected: " + obj.getClass().toString(), obj instanceof Person);
+ Person person = (Person) obj;
+ assertEquals("Andrey", person.getFirstName());
+ assertNull(person.getLastName());
+ assertEquals(99, person.getAge().intValue());
+}
+
+/**
+ * create instance using constructor arguments
+ */
+public void testGetConstructorBean() {
+ String data = "--- !org.yaml.snakeyaml.constructor.Person [ Andrey, Somov, 99 ]";
+ Object obj = construct(data);
+ assertNotNull(obj);
+ assertTrue(obj.getClass().toString(), obj instanceof Person);
+ Person person = (Person) obj;
+ assertEquals("Andrey", person.getFirstName());
+ assertEquals("Somov", person.getLastName());
+ assertEquals(99, person.getAge().intValue());
+}
+
+/**
+ * create instance using scalar argument
+ */
+public void testGetConstructorFromScalar() {
+ String data = "--- !org.yaml.snakeyaml.constructor.Person 'Somov'";
+ Object obj = construct(data);
+ assertNotNull(obj);
+ assertTrue(obj.getClass().toString(), obj instanceof Person);
+ Person person = (Person) obj;
+ assertNull("Andrey", person.getFirstName());
+ assertEquals("Somov", person.getLastName());
+ assertNull(person.getAge());
+}
+}}}
+
+Note if you want to limit objects to standard Java objects like List or Long you need
+[http://trac-hg.assembla.com/snakeyaml/browser/src/test/java/examples/SafeConstructorExampleTest.java to use SafeConstructor].
+{{{
+Loader loader = new Loader(new SafeConstructor());
+Yaml yaml = new Yaml(loader);
+}}}
+
+==== Providing the top level type ====
+
+It is possible to load a YAML document without any explicit tags. For instance, to load this document
+(example 2.27 from the [http://yaml.org/spec/1.1/#id859060 YAML specification])
+{{{
+invoice: 34843
+date : 2001-01-23
+billTo: &id001
+ given : Chris
+ family : Dumars
+ address:
+ lines: |
+ 458 Walkman Dr.
+ Suite #292
+ city : Royal Oak
+ state : MI
+ postal : 48046
+shipTo: *id001
+product:
+ - sku : BL394D
+ quantity : 4
+ description : Basketball
+ price : 450.00
+ - sku : BL4438H
+ quantity : 1
+ description : Super Hoop
+ price : 2392.00
+tax : 251.42
+total: 4443.52
+comments:
+ Late afternoon is best.
+ Backup contact is Nancy
+ Billsmer @ 338-4338.
+}}}
+into Invoice, Person, Address, Product instances the top level class in the object hierarchy
+[http://trac-hg.assembla.com/snakeyaml/browser/src/test/java/org/yaml/snakeyaml/Example2_27Test.java must be provided]:
+{{{
+Loader loader = new Loader(new Constructor(Invoice.class));
+Yaml yaml = new Yaml(loader);
+}}}
+SnakeYAML is using Reflection API to find out the class for all the properties (setters and public fields) on Invoice.
+Unfortunately because of erasure it is not possible to identify classes for type safe collections at runtime. The
+class information between <> is only available at compile time.
+
+=== Type safe collections ===
+
+In order to parse a collection which contains custom Java classes Yaml has to be provided with additional information.
+[http://trac-hg.assembla.com/snakeyaml/browser/src/main/java/org/yaml/snakeyaml/TypeDescription.java TypeDescription]
+serves the goal to collect more information and use it while loading/dumping.
+
+Let's say we have this document:
+{{{
+plate: 12-XP-F4
+wheels:
+- {id: 1}
+- {id: 2}
+- {id: 3}
+- {id: 4}
+- {id: 5}
+}}}
+and we would like to load this class
+{{{
+public class Car {
+ private String plate;
+ private List<Wheel> wheels;
+
+ public String getPlate() {
+ return plate;
+ }
+
+ public void setPlate(String plate) {
+ this.plate = plate;
+ }
+
+ public List<Wheel> getWheels() {
+ return wheels;
+ }
+
+ public void setWheels(List<Wheel> wheels) {
+ this.wheels = wheels;
+ }
+}
+}}}
+where 'wheels' property is a List of Wheel. In order to load Car (and create List<Wheel>)
+`TypeDescription` must be provided:
+{{{
+Constructor constructor = new Constructor(Car.class);//Car.class is root
+TypeDescription carDescription = new TypeDescription(Car.class);
+carDescription.putListPropertyType("wheels", Wheel.class);
+constructor.addTypeDefinition(carDescription);
+Loader loader = new Loader(constructor);
+Yaml yaml = new Yaml(loader);
+}}}
+The full example can be found
+[http://trac-hg.assembla.com/snakeyaml/browser/src/test/java/org/yaml/snakeyaml/constructor/TypeSafeCollectionsTest.java here]
+(testTypeSafeList()).
+
+A similar approach works for Maps. Please note that both keys and values of the Map can be of any type:
+{{{
+plate: 00-FF-Q2
+wheels:
+ ? {brand: Pirelli, id: 1}
+ : 2008-01-16
+ ? {brand: Dunkel, id: 2}
+ : 2002-12-24
+ ? {brand: Pirelli, id: 3}
+ : 2008-01-16
+ ? {brand: Pirelli, id: 4}
+ : 2008-01-16
+ ? {brand: Pirelli, id: 5}
+ : 2008-01-16
+}}}
+The class to be loaded:
+{{{
+public class MyCar {
+ private String plate;
+ private Map<MyWheel, Date> wheels;
+
+ public String getPlate() {
+ return plate;
+ }
+
+ public void setPlate(String plate) {
+ this.plate = plate;
+ }
+
+ public Map<MyWheel, Date> getWheels() {
+ return wheels;
+ }
+
+ public void setWheels(Map<MyWheel, Date> wheels) {
+ this.wheels = wheels;
+ }
+}
+}}}
+The [http://trac-hg.assembla.com/snakeyaml/browser/src/test/java/org/yaml/snakeyaml/constructor/TypeSafeCollectionsTest.java code]:
+{{{
+Constructor constructor = new Constructor(MyCar.class);
+TypeDescription carDescription = new TypeDescription(MyCar.class);
+carDescription.putMapPropertyType("wheels", MyWheel.class, Object.class);
+constructor.addTypeDefinition(carDescription);
+Loader loader = new Loader(constructor);
+Yaml yaml = new Yaml(loader);
+MyCar car = (MyCar) yaml.load(<see above>);
+}}}
+
+=== Dumping YAML ===
+
+The '''`Yaml.dump(Object data)`''' function accepts a Java object and produces a YAML document.
+(the source is [http://trac-hg.assembla.com/snakeyaml/browser/src/test/java/examples/DumpExampleTest.java here])
+{{{
+public void testDump() {
+ Map<String, Object> data = new HashMap<String, Object>();
+ data.put("name", "Silenthand Olleander");
+ data.put("race", "Human");
+ data.put("traits", new String[] { "ONE_HAND", "ONE_EYE" });
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(data);
+ System.out.println(output);
+}
+}}}
+{{{
+name: Silenthand Olleander
+traits: [ONE_HAND, ONE_EYE]
+race: Human
+}}}
+
+'''`Yaml.dump(Object data, Writer output)`''' will write the produced YAML document into
+the specified file/stream.
+
+{{{
+public void testDumpWriter() {
+ Map<String, Object> data = new HashMap<String, Object>();
+ data.put("name", "Silenthand Olleander");
+ data.put("race", "Human");
+ data.put("traits", new String[] { "ONE_HAND", "ONE_EYE" });
+ Yaml yaml = new Yaml();
+ StringWriter writer = new StringWriter();
+ yaml.dump(data, writer);
+ System.out.println(writer.toString());
+}
+}}}
+
+If you need to dump several YAML documents to a single stream, use the method
+'''`Yaml.dumpAll(Iterator<Object> data)`'''. It accepts an Iterator of
+Java objects to be serialized into a YAML document. A Writer can also be used.
+
+{{{
+public void testDumpMany() {
+ List<Integer> docs = new LinkedList<Integer>();
+ for (int i = 1; i < 4; i++) {
+ docs.add(i);
+ }
+ DumperOptions options = new DumperOptions();
+ options.explicitStart(true);
+ Yaml yaml = new Yaml(options);
+ System.out.println(yaml.dump(docs));
+ System.out.println(yaml.dumpAll(docs.iterator()));
+}
+}}}
+{{{
+--- [1, 2, 3]
+
+--- 1
+--- 2
+--- 3
+}}}
+
+You may even dump instances of `JavaBeans`.
+
+{{{
+public void testDumpCustomJavaClass() {
+ Hero hero = new Hero("Galain Ysseleg", -3, 2);
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(hero);
+ System.out.println(output);
+ assertEquals("!!examples.Hero {hp: -3, name: Galain Ysseleg, sp: 2}\n", output);
+}
+}}}
+{{{
+!!examples.Hero {hp: -3, name: Galain Ysseleg, sp: 2}
+}}}
+
+As you can see the `JavaBean` data is sorted althabetically.
+
+'''`DumperOptions`''' specifies
+formatting details for the emitter. For instance, you may set the
+preferred intendation and width, use the canonical YAML format or
+force preferred style for scalars and collections.
+{{{
+public void testDumperOptions() {
+ List<Integer> data = new LinkedList<Integer>();
+ for (int i = 0; i < 50; i++) {
+ data.add(i);
+ }
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(data);
+ System.out.println(output);
+ //
+ DumperOptions options = new DumperOptions();
+ options.setWidth(50);
+ options.setIndent(4);
+ yaml = new Yaml(options);
+ output = yaml.dump(data);
+ System.out.println(output);
+}
+}}}
+{{{
+[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
+ 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
+ 43, 44, 45, 46, 47, 48, 49]
+
+[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
+ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47, 48, 49]
+}}}
+Canonical output:
+{{{
+public void testDumperOptionsCanonical() {
+ List<Integer> data = new LinkedList<Integer>();
+ for (int i = 0; i < 5; i++) {
+ data.add(i);
+ }
+ DumperOptions options = new DumperOptions();
+ options.setCanonical(true);
+ Yaml yaml = new Yaml(options);
+ String output = yaml.dump(data);
+ System.out.println(output);
+}
+}}}
+{{{
+---
+!!seq [
+ !!int "0",
+ !!int "1",
+ !!int "2",
+ !!int "3",
+ !!int "4",
+]
+}}}
+{{{
+public void testDumperOptionsFlowStyle() {
+ List<Integer> data = new LinkedList<Integer>();
+ for (int i = 0; i < 5; i++) {
+ data.add(i);
+ }
+ DumperOptions options = new DumperOptions();
+ options.setDefaultFlowStyle(DumperOptions.DefaultFlowStyle.BLOCK);
+ Yaml yaml = new Yaml(options);
+ String output = yaml.dump(data);
+ System.out.println(output);
+}
+}}}
+{{{
+- 0
+- 1
+- 2
+- 3
+- 4
+}}}
+{{{
+public void testDumperOptionsStyle() {
+ List<Integer> data = new LinkedList<Integer>();
+ for (int i = 0; i < 5; i++) {
+ data.add(i);
+ }
+ DumperOptions options = new DumperOptions();
+ options.setDefaultStyle(DumperOptions.DefaultScalarStyle.DOUBLE_QUOTED);
+ Yaml yaml = new Yaml(options);
+ String output = yaml.dump(data);
+ System.out.println(output);
+}
+}}}
+{{{
+- !!int "0"
+- !!int "1"
+- !!int "2"
+- !!int "3"
+- !!int "4"
+}}}
+
+=== `JavaBeans` ===
+
+The spec says - "One of the main goals of the `JavaBeans` architecture is to provide a platform neutral component
+architecture."
+
+Avoiding global tags significantly improves ability to exchange the YAML documents between different
+platforms and languages.
+
+If the custom Java class conforms to the `JavaBean` specification it can be loaded and dumped
+without any extra code. For instance this `JavaBean`
+{{{
+public class CarWithWheel {
+ private String plate;
+ private String year;
+ private Wheel wheel;
+ private Object part;
+ private Map<String, Integer> map;
+
+ public String getPlate() {
+ return plate;
+ }
+
+ public void setPlate(String plate) {
+ this.plate = plate;
+ }
+
+ public Wheel getWheel() {
+ return wheel;
+ }
+
+ public void setWheel(Wheel wheel) {
+ this.wheel = wheel;
+ }
+
+ public Map<String, Integer> getMap() {
+ return map;
+ }
+
+ public void setMap(Map<String, Integer> map) {
+ this.map = map;
+ }
+
+ public Object getPart() {
+ return part;
+ }
+
+ public void setPart(Object part) {
+ this.part = part;
+ }
+
+ public String getYear() {
+ return year;
+ }
+
+ public void setYear(String year) {
+ this.year = year;
+ }
+}
+}}}
+{{{
+CarWithWheel car1 = new CarWithWheel();
+car1.setPlate("12-XP-F4");
+Wheel wheel = new Wheel();
+wheel.setId(2);
+car1.setWheel(wheel);
+Map<String, Integer> map = new HashMap<String, Integer>();
+map.put("id", 3);
+car1.setMap(map);
+car1.setPart(new Wheel(4));
+car1.setYear("2008");
+String output = new Yaml().dump(car1);
+}}}
+will be dumped as
+{{{
+!!package.CarWithWheel
+map: {id: 3}
+part: !!org.yaml.snakeyaml.constructor.Wheel {id: 4}
+plate: 12-XP-F4
+wheel: {id: 2}
+year: '2008'
+}}}
+Note that the 'part' property still has a global tag but the 'wheel' property does not
+(because the wheel's runtime class is the same as it is defined in the `CarWithWheel` class).
+
+The example for the above `JavaBean` can be found
+[http://trac-hg.assembla.com/snakeyaml/browser/src/test/java/org/yaml/snakeyaml/constructor/ImplicitTagsTest.java here]
+
+If it is nessesary to massage/skip the root global tag for the `JavaBean` it
+can be specified via `DumperOptions`.setExplicitRoot(String tag).
+
+There is a utility to parse `JavaBeans` - [http://trac-hg.assembla.com/snakeyaml/browser/src/main/java/org/yaml/snakeyaml/JavaBeanParser.java JavaBeanParser].
+All the methods of this utility are stateless and can be called from different Threads. The utility eliminates
+the need to cast returned instances to the specified class.
+
+=== Shortcuts ===
+
+There is a way to define local tags for custom classes.
+{{{
+!!org.yaml.snakeyaml.constructor.Car
+plate: 12-XP-F4
+wheels:
+- !!org.yaml.snakeyaml.constructor.Wheel {id: 1}
+- !!org.yaml.snakeyaml.constructor.Wheel {id: 2}
+- !!org.yaml.snakeyaml.constructor.Wheel {id: 3}
+- !!org.yaml.snakeyaml.constructor.Wheel {id: 4}
+- !!org.yaml.snakeyaml.constructor.Wheel {id: 5}
+}}}
+To eliminate long names while dumping Yaml
+[http://trac-hg.assembla.com/snakeyaml/browser/src/test/java/org/yaml/snakeyaml/constructor/ClassTagsTest.java should be configured]
+to use shortcuts:
+{{{
+Representer representer = new Representer();
+representer.putClassTag(Car.class, "!car");
+representer.putClassTag(Wheel.class, "tag:yaml.org,2002:map");
+Dumper dumper = new Dumper(representer, new DumperOptions());
+Yaml yaml = new Yaml(dumper);
+String output = yaml.dump(car);
+}}}
+This is the resulting output:
+{{{
+!car
+plate: 12-XP-F4
+wheels:
+- {id: 1}
+- {id: 2}
+- {id: 3}
+- {id: 4}
+- {id: 5}
+}}}
+Loader can be configured in a similar way:
+{{{
+Constructor constructor = new Constructor();
+constructor.putClassTag("!car", Car.class);
+Loader loader = new Loader(constructor);
+Yaml yaml = new Yaml(loader);
+}}}
+
+=== Constructors, representers, resolvers ===
+
+You may define your own application-specific tags. (the example's source is
+[http://trac-hg.assembla.com/snakeyaml/browser/src/test/java/examples/DiceExampleTest.java here])
+
+For instance, you may want to add a constructor
+and a representer for the following [http://trac-hg.assembla.com/snakeyaml/browser/src/test/java/examples/Dice.java Dice] class:
+{{{
+public class Dice {
+ private Integer a;
+ private Integer b;
+
+ public Dice(Integer a, Integer b) {
+ super();
+ this.a = a;
+ this.b = b;
+ }
+
+ public Integer getA() {
+ return a;
+ }
+
+ public Integer getB() {
+ return b;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof Dice) {
+ return toString().equals(obj.toString());
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return toString().hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return "Dice " + a + "d" + b;
+ }
+}
+}}}
+
+
+The default representation for '''`Dice`''' objects is not nice:
+{{{
+public void testRepresenter() throws IOException {
+ Dice dice = new Dice(3, 6);
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(dice);
+ System.out.println(output);
+}
+}}}
+{{{
+!!examples.Dice {a: 3, b: 6}
+}}}
+
+Suppose you want a '''`Dice`''' object to represented as '''`AdB`''' in YAML:
+{{{
+System.out.println(yaml.dump(new Dice(3,6)));
+
+3d6
+}}}
+
+First we define a representer that convert a dice object to scalar node
+with the tag `!dice` and register it.
+{{{
+class DiceRepresenter extends Representer {
+ public DiceRepresenter() {
+ this.representers.put(Dice.class, new RepresentDice());
+ }
+
+ private class RepresentDice implements Represent {
+ public Node representData(Object data) {
+ Dice dice = (Dice) data;
+ String value = dice.getA() + "d" + dice.getB();
+ return representScalar("!dice", value);
+ }
+ }
+}
+}}}
+
+Now you may dump an instance of the `Dice` object:
+{{{
+public void testDiceRepresenter() throws IOException {
+ Dice dice = new Dice(3, 6);
+ Map<String, Dice> data = new HashMap<String, Dice>();
+ data.put("gold", dice);
+ Yaml yaml = new Yaml(new Dumper(new DiceRepresenter(), new DumperOptions()));
+ String output = yaml.dump(data);
+ System.out.println(output);
+}
+}}}
+{{{
+{gold: !dice '10d6'}
+}}}
+
+Let us add the code to construct a Dice object:
+{{{
+class DiceConstructor extends Constructor {
+ public DiceConstructor() {
+ this.yamlConstructors.put("!dice", new ConstructDice());
+ }
+
+ private class ConstructDice implements Construct {
+ public Object construct(Node node) {
+ String val = (String) constructScalar(node);
+ int position = val.indexOf('d');
+ Integer a = Integer.parseInt(val.substring(0, position));
+ Integer b = Integer.parseInt(val.substring(position + 1));
+ return new Dice(a, b);
+ }
+ }
+}
+}}}
+
+Then you may load a `Dice` object as well:
+{{{
+public void testConstructor() throws IOException {
+ Yaml yaml = new Yaml(new Loader(new DiceConstructor()));
+ Object data = yaml.load("{initial hit points: !dice '8d4'}");
+ Map<String, Dice> map = (Map<String, Dice>) data;
+ assertEquals(new Dice(8, 4), map.get("initial hit points"));
+}
+}}}
+
+You might want to not specify the tag `!dice` everywhere. There is a way
+to teach SankeYAML that any untagged plain scalar that looks like XdY has
+the implicit tag `!dice`. Use '''`Yaml.addImplicitResolver(String tag, Pattern regexp, String first)`'''
+then you don't have to specify the tag to define a `Dice` object::
+{{{
+public void testImplicitResolver() throws IOException {
+ Yaml yaml = new Yaml(new Loader(new DiceConstructor()), new Dumper(new DiceRepresenter(),
+ new DumperOptions()));
+ yaml.addImplicitResolver("!dice", Pattern.compile("\\d+d\\d+"), "123456789");
+ // dump
+ Map<String, Dice> treasure = (Map<String, Dice>) new HashMap<String, Dice>();
+ treasure.put("treasure", new Dice(10, 20));
+ String output = yaml.dump(treasure);
+ System.out.println(output);
+ assertEquals("{treasure: 10d20}\n", output);
+ // load
+ Object data = yaml.load("{damage: 5d10}");
+ Map<String, Dice> map = (Map<String, Dice>) data;
+ assertEquals(new Dice(5, 10), map.get("damage"));
+}
+}}}
+{{{
+{treasure: 10d20}
+}}}
+
+== Enum ==
+SnakeYAML treats `Enum`s in a special way. (an example can be found
+[http://trac-hg.assembla.com/snakeyaml/browser/src/test/java/org/yaml/snakeyaml/EnumTest.java here])
+
+Normally an `Enum` requires an explicit global tag:
+{{{
+public void testDumpEnum() {
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(Suit.CLUBS);
+ assertEquals("!!org.yaml.snakeyaml.Suit 'CLUBS'\n", output);
+}
+
+public void testLoadEnum() {
+ Yaml yaml = new Yaml();
+ Suit suit = (Suit) yaml.load("!!org.yaml.snakeyaml.Suit 'CLUBS'");
+ assertEquals(Suit.CLUBS, suit);
+}
+}}}
+
+But if the Enum is a `JavaBean` property (and the class is implicitly defined) then the tags are not used:
+{{{
+public void testDumpEnumBean() {
+ DumperOptions options = new DumperOptions();
+ options.setDefaultFlowStyle(DumperOptions.DefaultFlowStyle.BLOCK);
+ Yaml yaml = new Yaml(options);
+ EnumBean bean = new EnumBean();
+ bean.setId(17);
+ bean.setSuit(Suit.SPADES);
+ String output = yaml.dump(bean);
+ System.out.println(output);
+}
+}}}
+{{{
+!!org.yaml.snakeyaml.EnumBean
+id: 17
+suit: SPADES
+}}}
+
+The same for loading:
+{{{
+public void testLoadEnumBean() {
+ Yaml yaml = new Yaml();
+ EnumBean bean = (EnumBean) yaml.load("!!org.yaml.snakeyaml.EnumBean\nid: 174\nsuit: CLUBS");
+ assertEquals(Suit.CLUBS, bean.getSuit());
+ assertEquals(174, bean.getId());
+}
+}}}
+
+== Threading ==
+
+Threads must have separate Yaml instances. Instances are cheap both in terms of time to create
+and memory to occupy. Only the very first instance is heavy because of static initializers for
+constants and regular expressions.
+
+Because Loader and Dumper are stateful they cannot be shared between
+different Yaml instances.
+
+== Spring ==
+
+Example of [http://trac-hg.assembla.com/snakeyaml/browser/src/test/resources/examples/spring.xml Spring definition]:
+(note: the scope is always 'prototype')
+{{{
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:util="http://www.springframework.org/schema/util" xmlns:p="http://www.springframework.org/schema/p"
+ xsi:schemaLocation="
+http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
+http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.0.xsd">
+
+ <!-- the most powerful way -->
+ <bean id="yamlConstructor" class="examples.CustomConstructor" scope="prototype" />
+ <bean id="yamlLoader" class="org.yaml.snakeyaml.Loader" scope="prototype">
+ <constructor-arg ref="yamlConstructor" />
+ </bean>
+ <bean id="yamlRepresenter" class="org.yaml.snakeyaml.representer.Representer" scope="prototype" />
+ <bean id="yamlOptions" class="org.yaml.snakeyaml.DumperOptions" scope="prototype">
+ <property name="indent" value="2" />
+ </bean>
+ <bean id="yamlDumper" class="org.yaml.snakeyaml.Dumper" scope="prototype">
+ <constructor-arg ref="yamlRepresenter" />
+ <constructor-arg ref="yamlOptions" />
+ </bean>
+ <bean id="snakeYaml" class="org.yaml.snakeyaml.Yaml" scope="prototype">
+ <constructor-arg ref="yamlLoader" />
+ <constructor-arg ref="yamlDumper" />
+ </bean>
+
+ <!-- for a single JavaBean -->
+ <bean id="beanConstructor" class="org.yaml.snakeyaml.constructor.Constructor" scope="prototype">
+ <constructor-arg value="org.yaml.snakeyaml.Invoice" />
+ </bean>
+ <bean id="beanLoader" class="org.yaml.snakeyaml.Loader" scope="prototype">
+ <constructor-arg ref="beanConstructor" />
+ </bean>
+ <bean id="javabeanYaml" class="org.yaml.snakeyaml.Yaml" scope="prototype">
+ <constructor-arg ref="beanLoader" />
+ </bean>
+
+ <!-- the simplest way -->
+ <bean id="standardYaml" class="org.yaml.snakeyaml.Yaml" scope="prototype" />
+</beans>
+}}}
+
+== Deviation from PyYAML ==
+
+ * SnakeYAML does not emit '...' (end of document) for simple documents
+ * SnakeYAML emits Unicode (not ASCII) by default
+
+== YAML syntax ==
+
+A good introduction to the YAML syntax is
+[http://yaml.org/spec/cvs/current.html#id857168 Chapter 2 of the YAML specification].
+
+You may also check [http://yaml4r.sourceforge.net/cookbook/ the YAML cookbook]. Note
+that it is focused on a Ruby implementation and uses the old YAML 1.0 syntax.
+
+Here we present most common YAML constructs together with the corresponding Java objects.
+
+
+=== Documents ===
+
+YAML stream is a collection of zero or more documents. An empty stream contains no documents.
+Documents are separated with '''`---`'''. Documents may optionally end with '''`...`'''.
+A single document may or may not be marked with '''`---`'''.
+
+Example of an implicit document:
+{{{
+- Multimedia
+- Internet
+- Education
+}}}
+
+Example of an explicit document:
+{{{
+---
+- Afterstep
+- CTWM
+- Oroborus
+...
+}}}
+
+Example of several documents in the same stream:
+{{{
+---
+- Ada
+- APL
+- ASP
+
+- Assembly
+- Awk
+---
+- Basic
+---
+- C
+- C# # Note that comments are denoted with ' #' (space and #).
+- C++
+- Cold Fusion
+}}}
+
+
+=== Block sequences ===
+
+In the block context, sequence entries are denoted by '''`- `''' (dash and space):
+{{{
+# YAML
+- The Dagger 'Narthanc'
+- The Dagger 'Nimthanc'
+- The Dagger 'Dethanc'
+}}}
+{{{
+# Java
+["The Dagger 'Narthanc'", "The Dagger 'Nimthanc'", "The Dagger 'Dethanc'"]
+}}}
+
+Block sequences can be nested:
+{{{
+# YAML
+-
+ - HTML
+ - LaTeX
+ - SGML
+ - VRML
+ - XML
+ - YAML
+-
+ - BSD
+ - GNU Hurd
+ - Linux
+}}}
+{{{
+# Java
+[['HTML', 'LaTeX', 'SGML', 'VRML', 'XML', 'YAML'], ['BSD', 'GNU Hurd', 'Linux']]
+}}}
+
+It's not necessary to start a nested sequence with a new line:
+{{{
+# YAML
+- 1.1
+- - 2.1
+ - 2.2
+- - - 3.1
+ - 3.2
+ - 3.3
+}}}
+{{{
+# Java
+[1.1, [2.1, 2.2], [[3.1, 3.2, 3.3]]]
+}}}
+
+A block sequence may be nested to a block mapping. Note that in this
+case it is not necessary to indent the sequence.
+{{{
+# YAML
+left hand:
+- Ring of Teleportation
+- Ring of Speed
+
+right hand:
+- Ring of Resist Fire
+- Ring of Resist Cold
+- Ring of Resist Poison
+}}}
+{{{
+# Java
+{'right hand': ['Ring of Resist Fire', 'Ring of Resist Cold', 'Ring of Resist Poison'],
+'left hand': ['Ring of Teleportation', 'Ring of Speed']}
+}}}
+
+
+=== Block mappings ===
+
+In the block context, keys and values of mappings are separated by '''`: `''' (colon and space):
+{{{
+# YAML
+base armor class: 0
+base damage: [4,4]
+plus to-hit: 12
+plus to-dam: 16
+plus to-ac: 0
+}}}
+{{{
+# Java
+{'plus to-hit': 12, 'base damage': [4, 4], 'base armor class': 0, 'plus to-ac': 0, 'plus to-dam': 16}
+}}}
+
+Complex keys are denoted with '''`? `''' (question mark and space):
+{{{
+# YAML
+? !!python/tuple [0,0]
+: The Hero
+? !!python/tuple [0,1]
+: Treasure
+? !!python/tuple [1,0]
+: Treasure
+? !!python/tuple [1,1]
+: The Dragon
+}}}
+{{{
+# Java
+{(0, 1): 'Treasure', (1, 0): 'Treasure', (0, 0): 'The Hero', (1, 1): 'The Dragon'}
+}}}
+
+Block mapping can be nested:
+{{{
+# YAML
+hero:
+ hp: 34
+ sp: 8
+ level: 4
+orc:
+ hp: 12
+ sp: 0
+ level: 2
+}}}
+{{{
+# Java
+{'hero': {'hp': 34, 'sp': 8, 'level': 4}, 'orc': {'hp': 12, 'sp': 0, 'level': 2}}
+}}}
+
+A block mapping may be nested in a block sequence:
+{{{
+# YAML
+- name: PyYAML
+ status: 4
+ license: MIT
+ language: Python
+- name: PySyck
+ status: 5
+ license: BSD
+ language: Python
+}}}
+{{{
+# Java
+[{'status': 4, 'language': 'Python', 'name': 'PyYAML', 'license': 'MIT'},
+{'status': 5, 'license': 'BSD', 'name': 'PySyck', 'language': 'Python'}]
+}}}
+
+
+=== Flow collections ===
+
+The syntax of flow collections in YAML is very close to the syntax of list and
+dictionary constructors in Python:
+{{{
+# YAML
+{ str: [15, 17], con: [16, 16], dex: [17, 18], wis: [16, 16], int: [10, 13], chr: [5, 8] }
+}}}
+{{{
+# Java
+{'dex': [17, 18], 'int': [10, 13], 'chr': [5, 8], 'wis': [16, 16], 'str': [15, 17], 'con': [16, 16]}
+}}}
+
+
+=== Scalars ===
+
+There are 5 styles of scalars in YAML: plain, single-quoted, double-quoted, literal, and folded:
+{{{
+# YAML
+plain: Scroll of Remove Curse
+single-quoted: 'EASY_KNOW'
+double-quoted: "?"
+literal: | # Borrowed from http://www.kersbergen.com/flump/religion.html
+ by hjw ___
+ __ /.-.\
+ / )_____________\\ Y
+ /_ /=== == === === =\ _\_
+ ( /)=== == === === == Y \
+ `-------------------( o )
+ \___/
+folded: >
+ It removes all ordinary curses from all equipped items.
+ Heavy or permanent curses are unaffected.
+}}}
+{{{
+# Java
+{'plain': 'Scroll of Remove Curse',
+'literal':
+ 'by hjw ___\n'
+ ' __ /.-.\\\n'
+ ' / )_____________\\\\ Y\n'
+ ' /_ /=== == === === =\\ _\\_\n'
+ '( /)=== == === === == Y \\\n'
+ ' `-------------------( o )\n'
+ ' \\___/\n',
+'single-quoted': 'EASY_KNOW',
+'double-quoted': '?',
+'folded': 'It removes all ordinary curses from all equipped items. Heavy or permanent curses are unaffected.\n'}
+}}}
+
+Each style has its own quirks. A plain scalar does not use indicators to denote its
+start and end, therefore it's the most restricted style. Its natural applications are
+names of attributes and parameters.
+
+Using single-quoted scalars, you may express any value that does not contain special characters.
+No escaping occurs for single quoted scalars except that duplicate quotes '''`''`''' are replaced
+with a single quote '''`'`'''.
+
+Double-quoted is the most powerful style and the only style that can express any scalar value.
+Double-quoted scalars allow ''escaping''. Using escaping sequences '''`\x**`''' and '''`\u****`''',
+you may express any ASCII or Unicode character.
+
+There are two kind of block scalar styles: '''literal''' and '''folded'''. The literal style is
+the most suitable style for large block of text such as source code. The folded style is similar
+to the literal style, but two consequent non-empty lines are joined to a single line separated
+by a space character.
+
+
+=== Aliases ===
+
+Using YAML you may represent objects of arbitrary graph-like structures. If you want to refer
+to the same object from different parts of a document, you need to use anchors and aliases.
+
+Anchors are denoted by the '''`&`''' indicator while aliases are denoted by '''`*`'''. For instance,
+the document
+{{{
+left hand: &A
+ name: The Bastard Sword of Eowyn
+ weight: 30
+right hand: *A
+}}}
+expresses the idea of a hero holding a heavy sword in both hands.
+
+SnakeYAML now fully supports recursive objects. For instance, the document
+{{{
+&A [ *A ]
+}}}
+will produce a list object containing a reference to itself.
+
+
+=== Tags ===
+
+Tags are used to denote the type of a YAML node. Standard YAML tags are defined at
+http://yaml.org/type/index.html.
+
+Tags may be implicit:
+{{{
+boolean: true
+integer: 3
+float: 3.14
+}}}
+{{{
+#!python
+{'boolean': True, 'integer': 3, 'float': 3.14}
+}}}
+
+or explicit:
+{{{
+boolean: !!bool "true"
+integer: !!int "3"
+float: !!float "3.14"
+}}}
+{{{
+#!python
+{'boolean': True, 'integer': 3, 'float': 3.14}
+}}}
+
+Plain scalars without explicitly defined tag are subject to implicit tag
+resolution. The scalar value is checked against a set of regular expressions
+and if one of them matches, the corresponding tag is assigned to the scalar.
+SnakeYAML allows an application to add custom implicit tag resolvers.
+
+
+== YAML tags and Java types ==
+
+The following table describes how nodes with different tags are converted
+to Java objects.
+
+|| '''YAML tag''' || '''Java type''' ||
+|| ''Standard YAML tags'' || ||
+|| `!!null` || `null` ||
+|| `!!bool` || `Boolean` ||
+|| `!!int` || `Integer, Long, BigInteger` ||
+|| `!!float` || `Double` ||
+|| `!!binary` || `String` ||
+|| `!!timestamp` || `java.util.Date`, `java.sql.Date` ||
+|| `!!omap`, `!!pairs` || `List` of `Object[]` ||
+|| `!!set` || `Set` ||
+|| `!!str` || `String` ||
+|| `!!seq` || `List` ||
+|| `!!map` || `Map` ||
+
+An example of loading and dumping [http://yaml.org/spec/1.1/#id858961 Global tags] can be found
+[http://trac-hg.assembla.com/snakeyaml/browser/src/test/java/org/yaml/snakeyaml/Example2_24Test.java here].
+
+== Collections ==
+
+Default implementations of collections are:
+ * ''List'': `LinkedList`
+ * ''Map'': `LinkedHashMap` (the order is implicitly defined)
+
+It is possible to define other default implementations. An example can be found
+[http://trac-hg.assembla.com/snakeyaml/browser/src/test/java/examples/CustomListExampleTest.java here] for List and
+[http://trac-hg.assembla.com/snakeyaml/browser/src/test/java/examples/CustomMapExampleTest.java here] for Map
+
+== Deviations from the specification ==
+
+''need to update this section''
+
+ * rules for tabs in YAML are confusing. We are close, but not there yet.
+ Perhaps both the spec and the parser should be fixed. Anyway, the best
+ rule for tabs in YAML is to not use them at all.
+ * Byte order mark. The initial BOM is stripped, but BOMs inside the stream
+ are considered as parts of the content. It can be fixed, but it's not
+ really important now.
+ * ~~Empty plain scalars are not allowed if alias or tag is specified.~~ This
+ is done to prevent anomalities like '''[ !tag, value]''', which can be
+ interpreted both as '''[ !<!tag,> value ]''' and '''[ !<!tag> "", "value" ]'''.
+ The spec should be fixed.
+ * Indentation of flow collections. The spec requires them to be indented
+ more than their block parent node. Unfortunately this rule renders many intuitively
+ correct constructs invalid, for instance,
+{{{
+block: {
+} # this is indentation violation according to the spec.
+}}}
+ * ':' is not allowed for plain scalars in the flow mode. ~~~'''{1:2}''' is
+ interpreted as '''{ 1 : 2 }'''.~~~
+
+
diff --git a/pom.xml b/pom.xml new file mode 100644 index 00000000..1071f536 --- /dev/null +++ b/pom.xml @@ -0,0 +1,163 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>SnakeYAML</groupId>
+ <artifactId>SnakeYAML</artifactId>
+ <version>1.1</version>
+ <packaging>jar</packaging>
+ <name>SnakeYAML</name>
+ <description>YAML 1.1 parser and emitter for Java</description>
+ <inceptionYear>2008</inceptionYear>
+ <url>http://trac-hg.assembla.com/snakeyaml/</url>
+ <issueManagement>
+ <system>Trac</system>
+ <url>http://trac-hg.assembla.com/snakeyaml/report</url>
+ </issueManagement>
+ <mailingLists>
+ <mailingList>
+ <name>SnakeYAML developers and users List</name>
+ <post>snakeyaml-core@googlegroups.com</post>
+ </mailingList>
+ </mailingLists>
+ <scm>
+ <connection>scm:hg:http://hg.assembla.com/snakeyaml</connection>
+ <url>http://trac-hg.assembla.com/snakeyaml/browser</url>
+ </scm>
+ <licenses>
+ <license>
+ <name>The MIT License</name>
+ <url>LICENSE</url>
+ </license>
+ </licenses>
+ <developers>
+ <developer>
+ <id>py4fun</id>
+ <name>Andrey Somov</name>
+ <email>py4fun@gmail.com</email>
+ </developer>
+ </developers>
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>3.8.2</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring</artifactId>
+ <version>2.5.6</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.5</source>
+ <target>1.5</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <includes>
+ <include>**/*Test.java</include>
+ </includes>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-eclipse-plugin</artifactId>
+ <configuration>
+ <buildOutputDirectory>bin</buildOutputDirectory>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>cobertura-maven-plugin</artifactId>
+ <version>2.2</version>
+ <configuration>
+ <check>
+ <totalBranchRate>80</totalBranchRate>
+ <totalLineRate>95</totalLineRate>
+ </check>
+ <formats>
+ <format>html</format>
+ <format>xml</format>
+ </formats>
+ </configuration>
+ <executions>
+ <execution>
+ <goals>
+ <goal>clean</goal>
+ <goal>check</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ <reporting>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-changes-plugin</artifactId>
+ <reportSets>
+ <reportSet>
+ <reports>
+ <report>changes-report</report>
+ </reports>
+ </reportSet>
+ </reportSets>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-report-plugin</artifactId>
+ <configuration>
+ <showSuccess>true</showSuccess>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>cobertura-maven-plugin</artifactId>
+ <configuration>
+ <formats>
+ <format>html</format>
+ <format>xml</format>
+ </formats>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>jxr-maven-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <reportSets>
+ <reportSet>
+ <id>html</id>
+ <configuration>
+ <doctitle>API for ${project.name} ${project.version}</doctitle>
+ <windowtitle>API for ${project.name} ${project.version}</windowtitle>
+ <testDoctitle>Test API for ${project.name} ${project.version}</testDoctitle>
+ <testWindowtitle>Test API for ${project.name} ${project.version}</testWindowtitle>
+ </configuration>
+ <reports>
+ <report>javadoc</report>
+ </reports>
+ </reportSet>
+ </reportSets>
+ </plugin>
+ </plugins>
+ </reporting>
+ <distributionManagement>
+ <repository>
+ <id>internal</id>
+ <name>SnakeYAML Repo</name>
+ <url>http://10.3.3.26:8080/archiva/repository/internal</url>
+ </repository>
+ </distributionManagement>
+</project>
diff --git a/src/changes/changes.xml b/src/changes/changes.xml new file mode 100644 index 00000000..8b4f7d18 --- /dev/null +++ b/src/changes/changes.xml @@ -0,0 +1,458 @@ +<document>
+ <properties>
+ <title>YAML 1.1 parser and emitter</title>
+ <author email="py4fun@gmail.com">Andrey Somov</author>
+ </properties>
+ <body>
+ <release version="1.1" date="2009-03-14" description="improve performance and test coverage">
+ <action dev="py4fun" type="add">
+ Introduce JavaBeanParser (2009-03-14)
+ </action>
+ <action dev="py4fun" type="add">
+ Introduce DumperOptions.Version enum (2009-03-13)
+ </action>
+ <action dev="py4fun" type="add">
+ Introduce DumperOptions.LineBreak enum (2009-03-10)
+ </action>
+ <action dev="py4fun" type="update">
+ Use byte[] for binary type. (2009-03-09)
+ </action>
+ <action dev="py4fun" type="update">
+ Restore Regular Expressions in Resolver. Ragel gives only 5% performance increase.
+ Fix a bug in Resolver with expanded regular expressions which caused the
+ performance problem. (2009-03-06)
+ </action>
+ <action dev="py4fun" type="add">
+ Better Spring support: it is now possible to create a constructor with a String
+ as the class name. (2009-03-05)
+ </action>
+ <action dev="py4fun" type="update">
+ Throw an exception when the same Loader or Dumper instance is shared between
+ different Yaml instances. Because they are statefull it is not Thread-safe. (2009-03-05)
+ </action>
+ <action dev="py4fun" type="add">
+ Add possibility to set a meaningful name for Yaml instance to be shown in toString(). (2009-03-05)
+ </action>
+ <action dev="py4fun" type="update">
+ Refactor: declare classes which are not expected to be extended as final. (2009-03-04)
+ </action>
+ <action dev="py4fun" type="update">
+ Refactor: use 'final' keyword to identify immutable fields. (2009-03-04)
+ </action>
+ <action dev="py4fun" type="update">
+ Refactor: do not use 'final' keyword for local variables. (2009-03-04)
+ </action>
+ <action dev="py4fun" type="fix">
+ Fix: respect implicit resolvers with 'null' as a first character. (2009-03-02)
+ </action>
+ <action dev="py4fun" type="update">
+ Refactor: use Character instead of String as a key for implicit resolvers. (2009-03-02)
+ </action>
+ <action dev="py4fun" type="add">
+ Use Ragel instead of Regular Expressions for implicit types. (2009-03-02)
+ </action>
+ <action dev="py4fun" type="fix">
+ Fix ticket #4: java.sql.Date not handled. Thanks to Christophe Desguez (2009-02-28)
+ </action>
+ <action dev="py4fun" type="add">
+ Introduce DumperOptions.DefaultFlowStyle enum (2009-02-24)
+ </action>
+ <action dev="py4fun" type="add">
+ Introduce DumperOptions.DefaultScalarStyle enum (2009-02-24)
+ </action>
+ <action dev="py4fun" type="update">
+ Refactor: use 'switch' with Enum instead of multiple 'if' statements to distinguish nodes (2009-02-19)
+ </action>
+ <action dev="py4fun" type="update">
+ Refactor: use Enum instead of String as NodeId (2009-02-19)
+ </action>
+ </release>
+ <release version="1.0.1" date="2009-02-18" description="implement Enum support">
+ <action dev="py4fun" type="fix">
+ Do not emit anchors for Enum (2009-02-18)
+ </action>
+ <action dev="py4fun" type="fix">
+ Enum as a JavaBean property (when the Enum class is implicitly defined) does
+ not need tags for both loading and dumping (2009-02-17)
+ </action>
+ <action dev="py4fun" type="fix">
+ Enum is emitted as a scalar node (2009-02-17)
+ </action>
+ <action dev="py4fun" type="fix">
+ Enum is parsed as a scalar node or as a JavaBean property (2009-02-17)
+ </action>
+ <action dev="py4fun" type="update">
+ Refactor: for performance ScannerImpl.stalePossibleSimpleKeys() does not copy key Set (2009-02-10)
+ </action>
+ <action dev="py4fun" type="update">
+ By default allowUnicode=true. If it is necessary to escape Unicode use
+ DumperOptions.setAllowUnicode(false) (2009-02-09)
+ </action>
+ <action dev="py4fun" type="add">
+ Implement allowUnicode setting (to escape Unicode characters on non UTF-8 terminals) (2009-02-09)
+ </action>
+ <action dev="py4fun" type="add">
+ Add possibility to specify tags for dumping (2009-02-09)
+ </action>
+ <action dev="py4fun" type="update">
+ Rename getExpRoot to getExplicitRoot to conform with
+ standard JavaBean naming convention (2009-02-09)
+ </action>
+ <action dev="py4fun" type="update">
+ Rename explictStart and explicitEnd to standard setters to conform with
+ standard JavaBean naming convention (2009-02-09)
+ </action>
+ <action dev="py4fun" type="fix">
+ Add possibility to specify a line break (2009-02-09)
+ </action>
+ </release>
+ <release version="1.0" date="2009-02-06" description="final 1.0 release">
+ <action dev="py4fun" type="fix">
+ Use LinkedHashMap for Emitter.tagPrefixes to respect the order (2009-02-06)
+ </action>
+ <action dev="py4fun" type="fix">
+ Use LinkedHashMap for ScannerImpl.possibleSimpleKeys to respect the key order (2009-02-05)
+ </action>
+ <action dev="py4fun" type="add">
+ Add a test to prove that Yaml instances are independent and can safely be used in
+ multithreaded environment like for instance a Servlet container (2009-02-05)
+ </action>
+ <action dev="py4fun" type="update">
+ The mailing list is renamed to snakeyaml-core to avoid a
+ name conflict in Google AppEngine (2009-02-03)
+ </action>
+ </release>
+ <release version="1.0rc2" date="2008-01-22" description="Improve JavaBeans support">
+ <action dev="py4fun" type="add">
+ Provide possibility to define/eliminate the root tag for JavaBeans. Avoiding global tags
+ helps to exchange YAML documents with other programming languages (2009-01-21)
+ </action>
+ <action dev="py4fun" type="fix">
+ Arrays as JavaBens properties are properly supported (2009-01-21)
+ </action>
+ <action dev="py4fun" type="update">
+ Do not emit redundant tags for JavaBeans (2009-01-20)
+ </action>
+ <action dev="py4fun" type="add">
+ Respect public fields in JavaBeans (2009-01-20)
+ </action>
+ </release>
+ <release version="1.0rc1" date="2009-01-16" description="Construct type safe collections">
+ <action dev="py4fun" type="update">
+ Replace String.getBytes(Charset charset) with String.getBytes(String charsetName) because
+ String.getBytes(Charset charset) was introduced only in Java 6 (2009-01-16)
+ </action>
+ <action dev="py4fun" type="update">
+ Replace LinkedList.pop() with removeFirst() because pop() was
+ introduced only in Java 6 (2009-01-16)
+ </action>
+ <action dev="py4fun" type="update">
+ Replace LinkedList.push() with addFirst() because push() was
+ introduced only in Java 6 (2009-01-16)
+ </action>
+ <action dev="py4fun" type="add">
+ Implement type safe Map as a property of custom Java class (2009-01-16)
+ </action>
+ <action dev="py4fun" type="add">
+ Implement type safe List as a property of custom Java class (2009-01-15)
+ </action>
+ <action dev="py4fun" type="update">
+ Construct interface does not use generics. The type information is set
+ to the Node (2009-01-15)
+ </action>
+ <action dev="py4fun" type="add">
+ Introduce TypeDescription as a single configuration option for a custom class (2009-01-15)
+ </action>
+ </release>
+ <release version="0.91" date="2008-01-14" description="Support shortcut tags for custom classes">
+ <action dev="py4fun" type="add">
+ Add possibility to define shortcut tags for custom classes while loading (2009-01-13)
+ </action>
+ <action dev="py4fun" type="add">
+ Add possibility to define shortcut tags for custom classes while dumping (2009-01-13)
+ </action>
+ <action dev="py4fun" type="add">
+ Construct List as a JavaBean property. But due to erasure only standard Java
+ classes created (2009-01-13)
+ </action>
+ <action dev="py4fun" type="add">
+ Import PyStructureTest from PyYAML (2009-01-13)
+ </action>
+ <action dev="py4fun" type="add">
+ Import canonical scanner and parser from PyYAML (2009-01-12)
+ </action>
+ </release>
+ <release version="0.9" date="2008-01-12" description="Add possibility to define a root class for Loader">
+ <action dev="py4fun" type="add">
+ Finish 2.27 example from the specification (2009-01-12)
+ </action>
+ <action dev="py4fun" type="add">
+ Add possibility to define a root class for Loader (2009-01-11)
+ </action>
+ <action dev="py4fun" type="update">
+ Use Java Generics in the Construct interface (2009-01-11)
+ </action>
+ <action dev="py4fun" type="update">
+ Use Java Generics in the Scanner interface (2009-01-08)
+ </action>
+ <action dev="py4fun" type="update">
+ Create ScannerIml only in ParserImpl (2009-01-08)
+ </action>
+ <action dev="py4fun" type="fix">
+ Import changeset 312 from PyYAML. Fix a bug in Emitter when writing folded scalars (2009-01-07)
+ </action>
+ </release>
+ <release version="0.8" date="2009-01-07" description="Import changes from PyYAML 3.08">
+ <action dev="py4fun" type="add">
+ Add possibility to use java.io.Reader as input. BOM must be respected. (2009-01-06)
+ </action>
+ <action dev="py4fun" type="update">
+ Import Changeset 308 from PyYAML: Refactored whitespace combination
+ detector in the scalar analyser. (2009-01-06)
+ </action>
+ <action dev="py4fun" type="update">
+ Import Changeset 313 from PyYAML: Emit an explicit document end indicator
+ when there is a possibility of ambiguous parsing. (2009-01-06)
+ </action>
+ <action dev="py4fun" type="update">
+ Use global tags (with !!) to dump Java custom instances. (2009-01-05)
+ </action>
+ <action dev="py4fun" type="update">
+ Use global tags (with !!) to load Java custom instances. (2009-01-05)
+ </action>
+ <action dev="py4fun" type="add">
+ Add example of defining a custom List and Map implementations. (2009-01-04)
+ </action>
+ <action dev="py4fun" type="fix">
+ Fix parsing Long.MIN_VALUE: respect the sign when parsing integers. (2009-01-04)
+ </action>
+ <action dev="py4fun" type="update">
+ when constructing integers try to create the first in the following order:
+ Integer -> Long -> BigInteger. (2009-01-02)
+ </action>
+ </release>
+ <release version="0.7" date="2008-12-20" description="Improve test coverage">
+ <action dev="py4fun" type="update">
+ Improve test coverage for constructor package (2008-12-20)
+ </action>
+ <action dev="py4fun" type="remove">
+ Remove support for "value" type because it is not used (2008-12-20)
+ </action>
+ <action dev="py4fun" type="update">
+ Require test coverage 95% (2008-12-19)
+ </action>
+ <action dev="py4fun" type="update">
+ Improve test coverage for Nodes (2008-12-19)
+ </action>
+ <action dev="py4fun" type="fix">
+ Fix dumping Date and better coverage for Representer (2008-12-19)
+ </action>
+ <action dev="py4fun" type="remove">
+ Remove unused code based on coverage report (2008-12-19)
+ </action>
+ <action dev="py4fun" type="remove">
+ Tokens are 100% covered by tests (2008-12-19)
+ </action>
+ <action dev="py4fun" type="remove">
+ Remove old tests (2008-12-18)
+ </action>
+ <action dev="py4fun" type="update">
+ Synchronized with PyYAML revision 307
+ </action>
+ </release>
+ <release version="0.6" date="2008-12-17" description="Documentation added">
+ <action dev="py4fun" type="add">
+ Many examples added to the Wiki page (2008-12-17)
+ </action>
+ <action dev="py4fun" type="update">
+ Public interface is using Iterator instead of Iterable (2008-12-17)
+ </action>
+ <action dev="py4fun" type="update">
+ Sort names when JavaBeans are represented (2008-12-15)
+ </action>
+ <action dev="py4fun" type="fix">
+ defaultFlowStyle for Dumper is configurable in DumperOptions (2008-12-12)
+ </action>
+ </release>
+ <release version="0.5" date="2008-12-12" description="Import PyYAML 3.06">
+ <action dev="py4fun" type="add">
+ Add possibility to define an implicit resolver. {359:63190d5bcd10} (2008-12-11)
+ </action>
+ <action dev="py4fun" type="add">
+ Add possibility to define an explicit constructor. {356:ccaa0df9ca98} (2008-12-11)
+ </action>
+ <action dev="py4fun" type="update">
+ Java objects can be constructed from mapping (JavaBeans), from sequence (constructor)
+ from scalar (constructor). (2008-12-10)
+ </action>
+ <action dev="py4fun" type="fix">
+ pairs tag works properly. (2008-12-08)
+ </action>
+ <action dev="py4fun" type="fix">
+ omap tag works properly. (2008-12-08)
+ </action>
+ <action dev="py4fun" type="add">
+ Implement possibility to define a custom Map implementation {332}. (2008-12-06)
+ </action>
+ <action dev="py4fun" type="add">
+ Implement possibility to define a custom List implementation {331:72c03254c184}. (2008-12-06)
+ </action>
+ <action dev="py4fun" type="add">
+ Path resolver is removed because it is not imported properly {330}. (2008-12-06)
+ </action>
+ <action dev="py4fun" type="add">
+ Constructor is overwritten completely. (2008-12-06)
+ </action>
+ <action dev="py4fun" type="add">
+ Implement possibility to define a custom Representer. (2008-12-01)
+ </action>
+ <action dev="py4fun" type="update">
+ Support arrays of reference types. Arrays of primitives are not supported
+ because Arrays.asList() does not work. (2008-12-01)
+ </action>
+ <action dev="py4fun" type="update">
+ Import change 300 for Emitter from PyYAML. (2008-12-01)
+ </action>
+ <action dev="py4fun" type="fix">
+ Fix Node identity to avoid aliases for simple types - [1, 1]. (2008-11-28)
+ </action>
+ <action dev="py4fun" type="update">
+ Recursive objects can be represented (but not yet constructed) (2008-11-28)
+ </action>
+ <action dev="py4fun" type="update">
+ Binary is represented back as String (2008-11-28)
+ </action>
+ <action dev="py4fun" type="update">
+ Re-write Representer classes from scratch (2008-11-28)
+ </action>
+ <action dev="py4fun" type="fix">
+ 'null' can be a key in a map (2008-11-21)
+ </action>
+ <action dev="py4fun" type="fix">
+ !!set tag is parsed properly (2008-11-21)
+ </action>
+ <action dev="py4fun" type="update">
+ Single characters 'Y', 'N', 'y' and 'n' are parsed as String opposed to boolean
+ as it is defined in the specification. This is how it is done in PyYAML (2008-11-21)
+ </action>
+ <action dev="py4fun" type="remove">
+ Constructor: because Java does not have generators 'deep' is not
+ imported from PyYAML (2008-11-19)
+ </action>
+ <action dev="py4fun" type="update">
+ Composer imported from PyYAML (2008-11-17)
+ </action>
+ <action dev="py4fun" type="update">
+ Resolver.resolve() is using simple boolean argument instead of array of booleans
+ as in PyYAML. (2008-11-18)
+ </action> + <action dev="py4fun" type="fix"> + Fix: 'set' type works. (2008-11-18) + </action>
+ <action dev="py4fun" type="update">
+ Rewrite Parser from scratch. (2008-11-17)
+ </action>
+ </release>
+ <release version="0.4" date="2008-11-11" description="Fix issues in Scanner">
+ <action dev="py4fun" type="update">
+ Move constants from Yaml interface to appropriate classes (2008-11-10)
+ </action>
+ <action dev="py4fun" type="update">
+ Interface change: Yaml dumpAll() methods accept Iterable (2008-11-10)
+ </action>
+ <action dev="py4fun" type="update">
+ Interface change: Yaml loadAll() methods return Iterable (2008-11-10)
+ </action>
+ <action dev="py4fun" type="fix">
+ Scanner: copy keys to avoid java.util.ConcurrentModificationException when removing
+ possible simple key (2008-11-10)
+ </action>
+ <action dev="py4fun" type="update">
+ Tag v0.3.1 (2008-11-08)
+ </action> + <action dev="py4fun" type="update"> + MappingNode requires Map as a value and SequenceNode requires + List as a value (2008-11-08) + </action> + <action dev="py4fun" type="update"> + Marks in a Token are required (2008-11-08) + </action> + <action dev="py4fun" type="remove"> + Remove prefixForward() method from Reader because it is not present + in PyYAML (2008-11-08) + </action> + <action dev="py4fun" type="fix"> + Fix a deviation with PyYAML in method scanBlockScalar(). + 'chomping' can be null. Fix a bug in JvYaml that the trailing '\n' in a + block scalar was removed.(2008-11-07) + </action>
+ <action dev="py4fun" type="fix">
+ Fix a deviation with PyYAML in method scanDirectiveIgnoredLine().
+ Put '#' instead of '"'. (2008-11-07)
+ </action>
+ <action dev="py4fun" type="add">
+ Restore from PyYAML the way the keys are parsed. (Restored methods are
+ stalePossibleSimpleKeys() and removePossibleSimpleKey().)
+ Fix issue http://code.google.com/p/jvyamlb/issues/detail?id=6. (2008-11-07)
+ </action>
+ <action dev="py4fun" type="update">
+ Refactor: put changed classes to 'org.yaml.snakeyaml' package. (2008-11-05)
+ </action>
+ <action dev="py4fun" type="update">
+ Move all the main() methods to the corresponding test classes. (2008-11-05)
+ </action>
+ <action dev="py4fun" type="update">
+ Change public interface. Rename YAML to Yaml. Remove all static methods from Yaml.
+ Factory and configuration must be injected at the constructor. This way is closer
+ to PyYAML API. (2008-11-05)
+ </action>
+ <action dev="py4fun" type="add">
+ Reader as in PyYAML is implemented. BOM is properly supported (2008-11-05)
+ </action>
+ <action dev="py4fun" type="add">
+ Restore Mark in Token as it is in PyYAML. Mark is not defined yet (2008-10-30)
+ </action>
+ <action dev="py4fun" type="fix">
+ Off-by-one in EmitterImpl.writeDoubleQuoted().
+ Fix issue: https://jvyaml.dev.java.net/issues/show_bug.cgi?id=11 (2008-10-28)
+ </action>
+ <action dev="py4fun" type="fix">
+ Respect Unicode characters.
+ Fix issue: https://jvyaml.dev.java.net/issues/show_bug.cgi?id=10 (2008-10-28)
+ </action>
+ <action dev="py4fun" type="fix">
+ Respect sign for float.
+ Fix issue: https://jvyaml.dev.java.net/issues/show_bug.cgi?id=13 (2008-10-28)
+ </action>
+ <action dev="py4fun" type="add">
+ Binary data is represented as ByteBuffer (2008-10-27)
+ </action>
+ <action dev="py4fun" type="fix">
+ When parsed, a timestamp in the canonical form (i.e, 2001-12-15T02:59:43.1Z) is
+ interpreted as if it is in the default time zone.
+ Fix issue: https://jvyaml.dev.java.net/issues/show_bug.cgi?id=7 (2008-10-27)
+ </action>
+ <action dev="py4fun" type="add">
+ Add Mark from PyYAML. It is not used yet. The JUnit test is migrated from PyYAML (2008-10-23)
+ </action>
+ <action dev="py4fun" type="update">
+ Apply SnakeYAML as the name of the library (2008-10-22)
+ </action>
+ <action dev="py4fun" type="update">
+ Reformat the source files (2008-10-22)
+ </action>
+ <action dev="py4fun" type="update">
+ Apply LICENSE info to source files (2008-10-22)
+ </action>
+ <action dev="py4fun" type="update">
+ Mavenize project. Apply standard Maven folder structure (2008-10-20)
+ </action>
+ </release>
+ <release version="0.2.1" date="2008-10-20" description="Import JvYaml from CVS">
+ <action dev="py4fun" type="add">
+ Import project from https://jvyaml.dev.java.net/ (2008-10-20)
+ </action>
+ </release>
+ </body>
+</document>
+
diff --git a/src/main/java/org/yaml/snakeyaml/Dumper.java b/src/main/java/org/yaml/snakeyaml/Dumper.java new file mode 100644 index 00000000..763ba731 --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/Dumper.java @@ -0,0 +1,56 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml;
+
+import java.io.Writer;
+import java.util.Iterator;
+
+import org.yaml.snakeyaml.emitter.Emitter;
+import org.yaml.snakeyaml.error.YAMLException;
+import org.yaml.snakeyaml.representer.Representer;
+import org.yaml.snakeyaml.resolver.Resolver;
+import org.yaml.snakeyaml.serializer.Serializer;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public class Dumper {
+ private final Representer representer;
+ private final DumperOptions options;
+ private boolean attached = false;
+
+ public Dumper(Representer representer, DumperOptions options) {
+ this.representer = representer;
+ this.options = options;
+ }
+
+ public Dumper(DumperOptions options) {
+ this(new Representer(options.getDefaultStyle().getChar(), options.getDefaultFlowStyle()
+ .getStyleBoolean()), options);
+ }
+
+ public void dump(Iterator<? extends Object> iter, Writer output, Resolver resolver) {
+ Serializer s = new Serializer(new Emitter(output, options), resolver, options);
+ try {
+ s.open();
+ while (iter.hasNext()) {
+ representer.represent(s, iter.next());
+ }
+ s.close();
+ } catch (java.io.IOException e) {
+ throw new YAMLException(e);
+ }
+ }
+
+ /**
+ * Because Dumper is stateful it cannot be shared
+ */
+ void setAttached() {
+ if (!attached) {
+ attached = true;
+ } else {
+ throw new YAMLException("Dumper cannot be shared.");
+ }
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/DumperOptions.java b/src/main/java/org/yaml/snakeyaml/DumperOptions.java new file mode 100644 index 00000000..49e69ae5 --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/DumperOptions.java @@ -0,0 +1,251 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml; + +import java.util.Map; + +import org.yaml.snakeyaml.emitter.Emitter; +import org.yaml.snakeyaml.error.YAMLException; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public class DumperOptions { + public enum DefaultScalarStyle { + DOUBLE_QUOTED(new Character('"')), SINGLE_QUOTED(new Character('\'')), LITERAL( + new Character('|')), FOLDED(new Character('>')), PLAIN(null); + private Character styleChar; + + private DefaultScalarStyle(Character defaultStyle) { + this.styleChar = defaultStyle; + } + + public Character getChar() { + return styleChar; + } + + @Override + public String toString() { + return "Scalar style: '" + styleChar + "'"; + } + } + + public enum DefaultFlowStyle { + FLOW(Boolean.TRUE), BLOCK(Boolean.FALSE), AUTO(null); + + private Boolean styleBoolean; + + private DefaultFlowStyle(Boolean defaultFlowStyle) { + styleBoolean = defaultFlowStyle; + } + + public Boolean getStyleBoolean() { + return styleBoolean; + } + + @Override + public String toString() { + return "Flow style: '" + styleBoolean + "'"; + } + } + + public enum LineBreak { + WIN("\r\n"), MAC("\r"), LINUX("\n"); + + private String lineBreak; + + private LineBreak(String lineBreak) { + this.lineBreak = lineBreak; + } + + public String getString() { + return lineBreak; + } + + @Override + public String toString() { + return "Line break: " + name(); + } + } + + public enum Version { + V1_0(new Integer[] { 1, 0 }), V1_1(new Integer[] { 1, 1 }); + + private Integer[] version; + + private Version(Integer[] version) { + this.version = version; + } + + public Integer[] getArray() { + return version; + } + + @Override + public String toString() { + return "Version: " + version[0] + "." + version[1]; + } + } + + private DefaultScalarStyle defaultStyle = DefaultScalarStyle.PLAIN; + private DefaultFlowStyle defaultFlowStyle = DefaultFlowStyle.AUTO; + private boolean canonical = false; + private boolean allowUnicode = true; + private int indent = 2; + private int bestWidth = 80; + private LineBreak lineBreak = LineBreak.LINUX; + private boolean explicitStart = false; + private boolean explicitEnd = false; + private String explicitRoot = null; + private Version version = null; + private Map<String, String> tags = null; + + public boolean isAllowUnicode() { + return allowUnicode; + } + + /** + * Specify whether to emit non-ASCII printable Unicode characters (to + * support ASCII terminals). The default value is true. + * + * @param allowUnicode + * - if allowUnicode is false then all non-ASCII characters are + * escaped + */ + public void setAllowUnicode(boolean allowUnicode) { + this.allowUnicode = allowUnicode; + } + + public DefaultScalarStyle getDefaultStyle() { + return defaultStyle; + } + + /** + * Set default style for scalars. See YAML 1.1 specification, 2.3 Scalars + * (http://yaml.org/spec/1.1/#id858081) + * + * @param defaultStyle + */ + public void setDefaultStyle(DefaultScalarStyle defaultStyle) { + if (defaultStyle == null) { + throw new NullPointerException("Use DefaultScalarStyle enum."); + } + this.defaultStyle = defaultStyle; + } + + public void setIndent(int indent) { + if (indent < Emitter.MIN_INDENT) { + throw new YAMLException("Indent must be at least " + Emitter.MIN_INDENT); + } + if (indent > Emitter.MAX_INDENT) { + throw new YAMLException("Indent must be at most " + Emitter.MAX_INDENT); + } + this.indent = indent; + } + + public int getIndent() { + return this.indent; + } + + public void setVersion(Version version) { + this.version = version; + } + + public Version getVersion() { + return this.version; + } + + public DumperOptions setCanonical(boolean canonical) { + this.canonical = canonical; + return this; + } + + public boolean isCanonical() { + return this.canonical; + } + + /** + * Specify the preferred width to emit scalars. When the scalar + * representation takes more then the preferred with the scalar will be + * split into a few lines. The default is 80. + * + * @param bestWidth + * - the preferred with for scalars. + */ + public void setWidth(int bestWidth) { + this.bestWidth = bestWidth; + } + + public int getWidth() { + return this.bestWidth; + } + + public LineBreak getLineBreak() { + return lineBreak; + } + + public void setDefaultFlowStyle(DefaultFlowStyle defaultFlowStyle) { + if (defaultFlowStyle == null) { + throw new NullPointerException("Use DefaultFlowStyle enum."); + } + this.defaultFlowStyle = defaultFlowStyle; + } + + public DefaultFlowStyle getDefaultFlowStyle() { + return defaultFlowStyle; + } + + public String getExplicitRoot() { + return explicitRoot; + } + + /** + * @param expRoot + * - tag to be used for the root node or <code>null</code> to get + * the default + */ + public void setExplicitRoot(String expRoot) { + if (expRoot == null) { + throw new NullPointerException("Root tag must be specified."); + } + this.explicitRoot = expRoot; + } + + /** + * Specify the line break to separate the lines. It is platform specific: + * Windows - "\r\n", MacOS - "\r", Linux - "\n". The default value is the + * one for Linux. + */ + public void setLineBreak(LineBreak lineBreak) { + if (lineBreak == null) { + throw new NullPointerException("Specify line break."); + } + this.lineBreak = lineBreak; + } + + public boolean isExplicitStart() { + return explicitStart; + } + + public void setExplicitStart(boolean explicitStart) { + this.explicitStart = explicitStart; + } + + public boolean isExplicitEnd() { + return explicitEnd; + } + + public void setExplicitEnd(boolean explicitEnd) { + this.explicitEnd = explicitEnd; + } + + public Map<String, String> getTags() { + return tags; + } + + public void setTags(Map<String, String> tags) { + this.tags = tags; + } + +} diff --git a/src/main/java/org/yaml/snakeyaml/JavaBeanParser.java b/src/main/java/org/yaml/snakeyaml/JavaBeanParser.java new file mode 100644 index 00000000..4495bf1f --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/JavaBeanParser.java @@ -0,0 +1,75 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml;
+
+import java.io.InputStream;
+import java.io.StringReader;
+
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.reader.UnicodeReader;
+import org.yaml.snakeyaml.resolver.Resolver;
+
+/**
+ * Convenience utility to parse JavaBeans. The returned instance is enforced to
+ * be of the same class as the provided argument. All the methods are Thread
+ * safe. When the YAML document contains a global tag with the class definition
+ * like '!!com.package.MyBean' it is ignored in favour of the runtime class.
+ */
+public class JavaBeanParser {
+
+ private JavaBeanParser() {
+ }
+
+ /**
+ * @param yaml
+ * - YAML document
+ * @param javabean
+ * - JavaBean class to be parsed
+ * @return parsed JavaBean
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> T load(String yaml, Class<T> javabean) {
+ Loader loader = createLoader(javabean);
+ return (T) loader.load(new StringReader(yaml));
+ }
+
+ /**
+ * Parse the first YAML document in a stream and produce the corresponding
+ * JavaBean.
+ *
+ * @param io
+ * - data to load from (BOM is respected and removed)
+ * @param javabean
+ * - JavaBean class to be parsed
+ * @return parsed JavaBean
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> T load(InputStream io, Class<T> javabean) {
+ Loader loader = createLoader(javabean);
+ return (T) loader.load(new UnicodeReader(io));
+ }
+
+ /**
+ * Parse the first YAML document in a stream and produce the corresponding
+ * Java object.
+ *
+ * @param io
+ * - data to load from (BOM must not be present)
+ * @param javabean
+ * - JavaBean class to be parsed
+ * @return parsed JavaBean
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> T load(java.io.Reader io, Class<T> javabean) {
+ Loader loader = createLoader(javabean);
+ return (T) loader.load(io);
+ }
+
+ private static Loader createLoader(Class<? extends Object> clazz) {
+ Loader loader = new Loader(new Constructor(clazz));
+ Resolver resolver = new Resolver();
+ loader.setResolver(resolver);
+ return loader;
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/Loader.java b/src/main/java/org/yaml/snakeyaml/Loader.java new file mode 100644 index 00000000..ffdc5eb5 --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/Loader.java @@ -0,0 +1,86 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml;
+
+import java.util.Iterator;
+
+import org.yaml.snakeyaml.composer.Composer;
+import org.yaml.snakeyaml.constructor.BaseConstructor;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.error.YAMLException;
+import org.yaml.snakeyaml.parser.ParserImpl;
+import org.yaml.snakeyaml.reader.Reader;
+import org.yaml.snakeyaml.resolver.Resolver;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public class Loader {
+ protected final BaseConstructor constructor;
+ protected Resolver resolver;
+ private boolean attached = false;
+
+ public Loader(BaseConstructor constructor) {
+ super();
+ this.constructor = constructor;
+ this.resolver = new Resolver();
+ }
+
+ public Loader() {
+ this(new Constructor());
+ }
+
+ public Object load(java.io.Reader io) {
+ Composer composer = new Composer(new ParserImpl(new Reader(io)), resolver);
+ constructor.setComposer(composer);
+ return constructor.getSingleData();
+ }
+
+ public Iterable<Object> loadAll(java.io.Reader yaml) {
+ Composer composer = new Composer(new ParserImpl(new Reader(yaml)), resolver);
+ this.constructor.setComposer(composer);
+ Iterator<Object> result = new Iterator<Object>() {
+ public boolean hasNext() {
+ return constructor.checkData();
+ }
+
+ public Object next() {
+ return constructor.getData();
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ return new YamlIterable(result);
+ }
+
+ private class YamlIterable implements Iterable<Object> {
+ private Iterator<Object> iterator;
+
+ public YamlIterable(Iterator<Object> iterator) {
+ this.iterator = iterator;
+ }
+
+ public Iterator<Object> iterator() {
+ return iterator;
+ }
+
+ }
+
+ public void setResolver(Resolver resolver) {
+ this.resolver = resolver;
+ }
+
+ /**
+ * Because Loader is stateful it cannot be shared
+ */
+ void setAttached() {
+ if (!attached) {
+ attached = true;
+ } else {
+ throw new YAMLException("Loader cannot be shared.");
+ }
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/TypeDescription.java b/src/main/java/org/yaml/snakeyaml/TypeDescription.java new file mode 100644 index 00000000..27eb1dcf --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/TypeDescription.java @@ -0,0 +1,145 @@ +package org.yaml.snakeyaml;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Provides additional runtime information necessary to create a custom Java
+ * instance.
+ */
+public final class TypeDescription {
+ private final Class<? extends Object> type;
+ private String tag;
+ private boolean root;
+ private Map<String, Class<? extends Object>> listProperties;
+ private Map<String, Class<? extends Object>> keyProperties;
+ private Map<String, Class<? extends Object>> valueProperties;
+
+ public TypeDescription(Class<? extends Object> clazz, String tag) {
+ this.type = clazz;
+ this.tag = tag;
+ listProperties = new HashMap<String, Class<? extends Object>>();
+ keyProperties = new HashMap<String, Class<? extends Object>>();
+ valueProperties = new HashMap<String, Class<? extends Object>>();
+ }
+
+ public TypeDescription(Class<? extends Object> clazz) {
+ this(clazz, null);
+ }
+
+ /**
+ * Get tag which shall be used to load or dump the type (class).
+ *
+ * @return tag to be used. It may be a tag for Language-Independent Types
+ * (http://www.yaml.org/type/)
+ */
+ public String getTag() {
+ return tag;
+ }
+
+ /**
+ * Set tag to be used to load or dump the type (class).
+ *
+ * @param tag
+ * - local or global tag
+ */
+ public void setTag(String tag) {
+ this.tag = tag;
+ }
+
+ /**
+ * Get represented type (class)
+ *
+ * @return type (class) to be described.
+ */
+ public Class<? extends Object> getType() {
+ return type;
+ }
+
+ /**
+ * Defines whether this type (class) is the root of the YAML document
+ *
+ * @return true if this type shall be used as a root of object hierarchy.
+ */
+ public boolean isRoot() {
+ return root;
+ }
+
+ /**
+ * Specify whether this type (class) should be serve as the root of the YAML
+ * document
+ *
+ * @param root
+ * - true if this type shall be used as a root of object
+ * hierarchy.
+ */
+ public void setRoot(boolean root) {
+ this.root = root;
+ }
+
+ /**
+ * Specify that the property is a type-safe <code>List</code>.
+ *
+ * @param property
+ * - name of the JavaBean property
+ * @param type
+ * - class of List values
+ */
+ public void putListPropertyType(String property, Class<? extends Object> type) {
+ listProperties.put(property, type);
+ }
+
+ /**
+ * Get class of List values for provided JavaBean property.
+ *
+ * @param property
+ * - property name
+ * @return class of List values
+ */
+ public Class<? extends Object> getListPropertyType(String property) {
+ return listProperties.get(property);
+ }
+
+ /**
+ * Specify that the property is a type-safe <code>Map</code>.
+ *
+ * @param property
+ * - property name of this JavaBean
+ * @param key
+ * - class of keys in Map
+ * @param value
+ * - class of values in Map
+ */
+ public void putMapPropertyType(String property, Class<? extends Object> key,
+ Class<? extends Object> value) {
+ keyProperties.put(property, key);
+ valueProperties.put(property, value);
+ }
+
+ /**
+ * Get keys type info for this JavaBean
+ *
+ * @param property
+ * - property name of this JavaBean
+ * @return class of keys in the Map
+ */
+ public Class<? extends Object> getMapKeyType(String property) {
+ return keyProperties.get(property);
+ }
+
+ /**
+ * Get values type info for this JavaBean
+ *
+ * @param property
+ * - property name of this JavaBean
+ * @return class of values in the Map
+ */
+ public Class<? extends Object> getMapValueType(String property) {
+ return valueProperties.get(property);
+ }
+
+ @Override
+ public String toString() {
+ return "TypeDescription for " + getType() + " (tag='" + getTag() + "')";
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/Yaml.java b/src/main/java/org/yaml/snakeyaml/Yaml.java new file mode 100644 index 00000000..f99a286d --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/Yaml.java @@ -0,0 +1,223 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml;
+
+import java.io.InputStream;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import org.yaml.snakeyaml.reader.UnicodeReader;
+import org.yaml.snakeyaml.resolver.Resolver;
+
+/**
+ * Public YAML interface. Each Thread must have its own instance.
+ */
+public class Yaml {
+ private final Dumper dumper;
+ private final Loader loader;
+ private final Resolver resolver;
+ private String name;
+
+ public Yaml(DumperOptions options) {
+ this(new Loader(), new Dumper(options));
+ }
+
+ public Yaml(Dumper dumper) {
+ this(new Loader(), dumper);
+ }
+
+ public Yaml(Loader loader) {
+ this(loader, new Dumper(new DumperOptions()));
+ }
+
+ /**
+ * Create Yaml instance. It is safe to create a few instances and use them
+ * in different Threads.
+ *
+ * @param loader
+ * - Loader to parse incoming documents
+ * @param dumper
+ * - Dumper to emit outgoing objects
+ */
+ public Yaml(Loader loader, Dumper dumper) {
+ this.loader = loader;
+ loader.setAttached();
+ this.dumper = dumper;
+ dumper.setAttached();
+ this.resolver = new Resolver();
+ this.loader.setResolver(resolver);
+ this.name = "Yaml:" + System.identityHashCode(this);
+ }
+
+ public Yaml() {
+ this(new Loader(), new Dumper(new DumperOptions()));
+ }
+
+ /**
+ * Serialize a Java object into a YAML String.
+ *
+ * @param data
+ * - Java object to be Serialized to YAML
+ * @return YAML String
+ */
+ public String dump(Object data) {
+ List<Object> lst = new ArrayList<Object>(1);
+ lst.add(data);
+ return dumpAll(lst.iterator());
+ }
+
+ /**
+ * Serialize a sequence of Java objects into a YAML String.
+ *
+ * @param data
+ * - Iterator with Objects
+ * @return - YAML String with all the objects in proper sequence
+ */
+ public String dumpAll(Iterator<? extends Object> data) {
+ StringWriter buffer = new StringWriter();
+ dumpAll(data, buffer);
+ return buffer.toString();
+ }
+
+ /**
+ * Serialize a Java object into a YAML stream.
+ *
+ * @param data
+ * - Java object to be Serialized to YAML
+ * @param output
+ * - stream to write to
+ */
+ public void dump(Object data, Writer output) {
+ List<Object> lst = new ArrayList<Object>(1);
+ lst.add(data);
+ dumpAll(lst.iterator(), output);
+ }
+
+ /**
+ * Serialize a sequence of Java objects into a YAML stream.
+ *
+ * @param data
+ * - Iterator with Objects
+ * @param output
+ * - stream to write to
+ */
+ public void dumpAll(Iterator<? extends Object> data, Writer output) {
+ dumper.dump(data, output, resolver);
+ }
+
+ /**
+ * Parse the first YAML document in a String and produce the corresponding
+ * Java object. (Because the encoding in known BOM is not respected.)
+ *
+ * @param yaml
+ * - YAML data to load from (BOM must not be present)
+ * @return parsed object
+ */
+ public Object load(String yaml) {
+ return loader.load(new StringReader(yaml));
+ }
+
+ /**
+ * Parse the first YAML document in a stream and produce the corresponding
+ * Java object.
+ *
+ * @param io
+ * - data to load from (BOM is respected and removed)
+ * @return parsed object
+ */
+ public Object load(InputStream io) {
+ return loader.load(new UnicodeReader(io));
+ }
+
+ /**
+ * Parse the first YAML document in a stream and produce the corresponding
+ * Java object.
+ *
+ * @param io
+ * - data to load from (BOM must not be present)
+ * @return parsed object
+ */
+ public Object load(java.io.Reader io) {
+ return loader.load(io);
+ }
+
+ /**
+ * Parse all YAML documents in a String and produce corresponding Java
+ * objects.
+ *
+ * @param yaml
+ * - YAML data to load from (BOM must not be present)
+ * @return an iterator over the parsed Java objects in this String in proper
+ * sequence
+ */
+ public Iterable<Object> loadAll(java.io.Reader yaml) {
+ return loader.loadAll(yaml);
+ }
+
+ /**
+ * Parse all YAML documents in a String and produce corresponding Java
+ * objects. (Because the encoding in known BOM is not respected.)
+ *
+ * @param yaml
+ * - YAML data to load from (BOM must not be present)
+ * @return an iterator over the parsed Java objects in this String in proper
+ * sequence
+ */
+ public Iterable<Object> loadAll(String yaml) {
+ return loadAll(new StringReader(yaml));
+ }
+
+ /**
+ * Parse all YAML documents in a stream and produce corresponding Java
+ * objects.
+ *
+ * @param yaml
+ * - YAML data to load from (BOM is respected and ignored)
+ * @return an iterator over the parsed Java objects in this stream in proper
+ * sequence
+ */
+ public Iterable<Object> loadAll(InputStream yaml) {
+ return loadAll(new UnicodeReader(yaml));
+ }
+
+ /**
+ * Add an implicit scalar detector. If an implicit scalar value matches the
+ * given regexp, the corresponding tag is assigned to the scalar. first is a
+ * sequence of possible initial characters or null (which means any).
+ *
+ * @param tag
+ * - tag to assign to the node
+ * @param regexp
+ * - regular expression to match against
+ * @param first
+ * - a sequence of possible initial characters or None
+ */
+ public void addImplicitResolver(String tag, Pattern regexp, String first) {
+ resolver.addImplicitResolver(tag, regexp, first);
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Set a meaningful name to be shown in toString()
+ *
+ * @param name
+ * - human readable name
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/composer/Composer.java b/src/main/java/org/yaml/snakeyaml/composer/Composer.java new file mode 100644 index 00000000..c95d5e0c --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/composer/Composer.java @@ -0,0 +1,181 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.composer; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.yaml.snakeyaml.events.AliasEvent; +import org.yaml.snakeyaml.events.Event; +import org.yaml.snakeyaml.events.MappingEndEvent; +import org.yaml.snakeyaml.events.MappingStartEvent; +import org.yaml.snakeyaml.events.NodeEvent; +import org.yaml.snakeyaml.events.ScalarEvent; +import org.yaml.snakeyaml.events.SequenceEndEvent; +import org.yaml.snakeyaml.events.SequenceStartEvent; +import org.yaml.snakeyaml.events.StreamEndEvent; +import org.yaml.snakeyaml.events.StreamStartEvent; +import org.yaml.snakeyaml.nodes.CollectionNode; +import org.yaml.snakeyaml.nodes.MappingNode; +import org.yaml.snakeyaml.nodes.Node; +import org.yaml.snakeyaml.nodes.NodeId; +import org.yaml.snakeyaml.nodes.ScalarNode; +import org.yaml.snakeyaml.nodes.SequenceNode; +import org.yaml.snakeyaml.parser.Parser; +import org.yaml.snakeyaml.resolver.Resolver; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public class Composer { + private final Parser parser; + private final Resolver resolver; + private final Map<String, Node> anchors; + + public Composer(Parser parser, Resolver resolver) { + this.parser = parser; + this.resolver = resolver; + this.anchors = new HashMap<String, Node>(); + } + + public boolean checkNode() { + // Drop the STREAM-START event. + if (parser.checkEvent(StreamStartEvent.class)) { + parser.getEvent(); + } + // If there are more documents available? + return !parser.checkEvent(StreamEndEvent.class); + } + + public Node getNode() { + // Get the root node of the next document. + if (!parser.checkEvent(StreamEndEvent.class)) { + return composeDocument(); + } else { + return (Node) null; + } + } + + public Node getSingleNode() { + // Drop the STREAM-START event. + parser.getEvent(); + // Compose a document if the stream is not empty. + Node document = null; + if (!parser.checkEvent(StreamEndEvent.class)) { + document = composeDocument(); + } + // Ensure that the stream contains no more documents. + if (!parser.checkEvent(StreamEndEvent.class)) { + Event event = parser.getEvent(); + throw new ComposerException("expected a single document in the stream", document + .getStartMark(), "but found another document", event.getStartMark()); + } + // Drop the STREAM-END event. + parser.getEvent(); + return document; + } + + private Node composeDocument() { + // Drop the DOCUMENT-START event. + parser.getEvent(); + // Compose the root node. + Node node = composeNode(null, null); + // Drop the DOCUMENT-END event. + parser.getEvent(); + this.anchors.clear(); + return node; + } + + private Node composeNode(Node parent, Object index) { + if (parser.checkEvent(AliasEvent.class)) { + AliasEvent event = (AliasEvent) parser.getEvent(); + String anchor = event.getAnchor(); + if (!anchors.containsKey(anchor)) { + throw new ComposerException(null, null, "found undefined alias " + anchor, event + .getStartMark()); + } + return (Node) anchors.get(anchor); + } + NodeEvent event = (NodeEvent) parser.peekEvent(); + String anchor = null; + anchor = event.getAnchor(); + if (anchor != null) { + if (anchors.containsKey(anchor)) { + throw new ComposerException("found duplicate anchor " + anchor + + "; first occurence", this.anchors.get(anchor).getStartMark(), + "second occurence", event.getStartMark()); + } + } + // resolver.descendResolver(parent, index); + Node node = null; + if (parser.checkEvent(ScalarEvent.class)) { + node = composeScalarNode(anchor); + } else if (parser.checkEvent(SequenceStartEvent.class)) { + node = composeSequenceNode(anchor); + } else { + node = composeMappingNode(anchor); + } + // resolver.ascendResolver(); + return node; + } + + private Node composeScalarNode(String anchor) { + ScalarEvent ev = (ScalarEvent) parser.getEvent(); + String tag = ev.getTag(); + if (tag == null || tag.equals("!")) { + tag = resolver.resolve(NodeId.scalar, ev.getValue(), ev.getImplicit()[0]); + } + Node node = new ScalarNode(tag, ev.getValue(), ev.getStartMark(), ev.getEndMark(), ev + .getStyle()); + if (anchor != null) { + anchors.put(anchor, node); + } + return node; + } + + @SuppressWarnings("unchecked") + private Node composeSequenceNode(String anchor) { + SequenceStartEvent startEvent = (SequenceStartEvent) parser.getEvent(); + String tag = startEvent.getTag(); + if (tag == null || tag.equals("!")) { + tag = resolver.resolve(NodeId.sequence, null, startEvent.getImplicit()); + } + CollectionNode node = new SequenceNode(tag, new LinkedList<Node>(), startEvent + .getStartMark(), null, startEvent.getFlowStyle()); + if (anchor != null) { + anchors.put(anchor, node); + } + int index = 0; + while (!parser.checkEvent(SequenceEndEvent.class)) { + ((List<Object>) node.getValue()).add(composeNode(node, new Integer(index))); + index++; + } + Event endEvent = parser.getEvent(); + node.setEndMark(endEvent.getEndMark()); + return node; + } + + private Node composeMappingNode(String anchor) { + MappingStartEvent startEvent = (MappingStartEvent) parser.getEvent(); + String tag = startEvent.getTag(); + if (tag == null || tag.equals("!")) { + tag = resolver.resolve(NodeId.mapping, null, startEvent.getImplicit()); + } + MappingNode node = new MappingNode(tag, new LinkedList<Node[]>(), + startEvent.getStartMark(), null, startEvent.getFlowStyle()); + if (anchor != null) { + anchors.put(anchor, node); + } + while (!parser.checkEvent(MappingEndEvent.class)) { + Node itemKey = composeNode(node, null); + Node itemValue = composeNode(node, itemKey); + node.getValue().add(new Node[] { itemKey, itemValue });// + } + Event endEvent = parser.getEvent(); + node.setEndMark(endEvent.getEndMark()); + return node; + } +} diff --git a/src/main/java/org/yaml/snakeyaml/composer/ComposerException.java b/src/main/java/org/yaml/snakeyaml/composer/ComposerException.java new file mode 100644 index 00000000..9fda8087 --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/composer/ComposerException.java @@ -0,0 +1,19 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.composer; + +import org.yaml.snakeyaml.error.Mark; +import org.yaml.snakeyaml.error.MarkedYAMLException; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public class ComposerException extends MarkedYAMLException { + private static final long serialVersionUID = 2146314636913113935L; + + protected ComposerException(String context, Mark contextMark, String problem, Mark problemMark) { + super(context, contextMark, problem, problemMark); + } + +} diff --git a/src/main/java/org/yaml/snakeyaml/constructor/BaseConstructor.java b/src/main/java/org/yaml/snakeyaml/constructor/BaseConstructor.java new file mode 100644 index 00000000..704c1f54 --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/constructor/BaseConstructor.java @@ -0,0 +1,152 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.constructor; + +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.yaml.snakeyaml.composer.Composer; +import org.yaml.snakeyaml.nodes.MappingNode; +import org.yaml.snakeyaml.nodes.Node; +import org.yaml.snakeyaml.nodes.ScalarNode; +import org.yaml.snakeyaml.nodes.SequenceNode; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public class BaseConstructor { + protected final Map<String, Construct> yamlConstructors = new HashMap<String, Construct>(); + + private Composer composer; + private final Map<Node, Object> constructedObjects; + private final Map<Node, Object> recursiveObjects; + + protected Class<? extends Object> rootType; + + public BaseConstructor() { + constructedObjects = new HashMap<Node, Object>(); + recursiveObjects = new HashMap<Node, Object>(); + rootType = Object.class; + } + + public void setComposer(Composer composer) { + this.composer = composer; + } + + public boolean checkData() { + // If there are more documents available? + return composer.checkNode(); + } + + public Object getData() { + // Construct and return the next document. + composer.checkNode(); + Node node = composer.getNode(); + node.setType(rootType); + return constructDocument(node); + } + + public Object getSingleData() { + // Ensure that the stream contains a single document and construct it + Node node = composer.getSingleNode(); + if (node != null) { + node.setType(rootType); + return constructDocument(node); + } + return null; + } + + private Object constructDocument(Node node) { + Object data = constructObject(node); + constructedObjects.clear(); + recursiveObjects.clear(); + return data; + } + + protected Object constructObject(Node node) { + if (constructedObjects.containsKey(node)) { + return constructedObjects.get(node); + } + if (recursiveObjects.containsKey(node)) { + throw new ConstructorException(null, null, "found unconstructable recursive node", node + .getStartMark()); + } + recursiveObjects.put(node, null); + Object data = callConstructor(node); + constructedObjects.put(node, data); + recursiveObjects.remove(node); + return data; + } + + protected Object callConstructor(Node node) { + Object data = null; + Construct constructor = null; + constructor = yamlConstructors.get(node.getTag()); + if (constructor == null) { + constructor = yamlConstructors.get(null); + data = constructor.construct(node); + } else { + data = constructor.construct(node); + } + return data; + } + + protected Object constructScalar(ScalarNode node) { + return node.getValue(); + } + + protected List<Object> createDefaultList(int initSize) { + return new LinkedList<Object>(); + } + + protected List<? extends Object> constructSequence(SequenceNode node) { + List<Node> nodeValue = (List<Node>) node.getValue(); + List<Object> result = createDefaultList(nodeValue.size()); + for (Node child : nodeValue) { + result.add(constructObject(child)); + } + return result; + } + + protected Map<Object, Object> createDefaultMap() { + // respect order from YAML document + return new LinkedHashMap<Object, Object>(); + } + + protected Map<Object, Object> constructMapping(MappingNode node) { + Map<Object, Object> mapping = createDefaultMap(); + List<Node[]> nodeValue = (List<Node[]>) node.getValue(); + for (Node[] tuple : nodeValue) { + Node keyNode = tuple[0]; + Node valueNode = tuple[1]; + Object key = constructObject(keyNode); + if (key != null) { + try { + key.hashCode();// check circular dependencies + } catch (Exception e) { + throw new ConstructorException("while constructing a mapping", node + .getStartMark(), "found unacceptable key " + key, tuple[0] + .getStartMark()); + } + } + Object value = constructObject(valueNode); + mapping.put(key, value); + } + return mapping; + } + // TODO protected List<Object[]> constructPairs(MappingNode node) { + // List<Object[]> pairs = new LinkedList<Object[]>(); + // List<Node[]> nodeValue = (List<Node[]>) node.getValue(); + // for (Iterator<Node[]> iter = nodeValue.iterator(); iter.hasNext();) { + // Node[] tuple = iter.next(); + // Object key = constructObject(Object.class, tuple[0]); + // Object value = constructObject(Object.class, tuple[1]); + // pairs.add(new Object[] { key, value }); + // } + // return pairs; + // } +} diff --git a/src/main/java/org/yaml/snakeyaml/constructor/Construct.java b/src/main/java/org/yaml/snakeyaml/constructor/Construct.java new file mode 100644 index 00000000..55e27b06 --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/constructor/Construct.java @@ -0,0 +1,10 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.constructor;
+
+import org.yaml.snakeyaml.nodes.Node;
+
+public interface Construct {
+ public Object construct(Node node);
+}
diff --git a/src/main/java/org/yaml/snakeyaml/constructor/Constructor.java b/src/main/java/org/yaml/snakeyaml/constructor/Constructor.java new file mode 100644 index 00000000..1a0b3242 --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/constructor/Constructor.java @@ -0,0 +1,348 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.constructor; + +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.lang.reflect.Array; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.math.BigInteger; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.yaml.snakeyaml.TypeDescription; +import org.yaml.snakeyaml.error.YAMLException; +import org.yaml.snakeyaml.introspector.FieldProperty; +import org.yaml.snakeyaml.introspector.MethodProperty; +import org.yaml.snakeyaml.introspector.Property; +import org.yaml.snakeyaml.nodes.MappingNode; +import org.yaml.snakeyaml.nodes.Node; +import org.yaml.snakeyaml.nodes.ScalarNode; +import org.yaml.snakeyaml.nodes.SequenceNode; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public class Constructor extends SafeConstructor { + private final Map<String, Class<? extends Object>> typeTags; + private final Map<Class<? extends Object>, TypeDescription> typeDefinitions; + + public Constructor() { + this(Object.class); + } + + public Constructor(Class<? extends Object> theRoot) { + if (theRoot == null) { + throw new NullPointerException("Root type must be provided."); + } + this.yamlConstructors.put(null, new ConstuctYamlObject()); + rootType = theRoot; + typeTags = new HashMap<String, Class<? extends Object>>(); + typeDefinitions = new HashMap<Class<? extends Object>, TypeDescription>(); + } + + /** + * Create Constructor for a class which does not have to be in the classpath + * or for a definition from a Spring ApplicationContext. + * + * @param theRoot + * - fully qualified class name of the root JavaBean + * @throws ClassNotFoundException + */ + public Constructor(String theRoot) throws ClassNotFoundException { + this(Class.forName(check(theRoot))); + } + + private static final String check(String s) { + if (s == null) { + throw new NullPointerException("Root type must be provided."); + } + if (s.trim().length() == 0) { + throw new YAMLException("Root type must be provided."); + } + return s; + } + + /** + * Make YAML aware how to parse a custom Class. If there is no root Class + * assigned in constructor then the 'root' property of this definition is + * respected. + * + * @param definition + * to be added to the Constructor + * @return the previous value associated with <tt>definition</tt>, or + * <tt>null</tt> if there was no mapping for <tt>definition</tt>. + */ + public TypeDescription addTypeDescription(TypeDescription definition) { + if (definition == null) { + throw new NullPointerException("TypeDescription is required."); + } + if (rootType == Object.class && definition.isRoot()) { + rootType = definition.getType(); + } + String tag = definition.getTag(); + typeTags.put(tag, definition.getType()); + return typeDefinitions.put(definition.getType(), definition); + } + + private class ConstuctYamlObject implements Construct { + @SuppressWarnings("unchecked") + public Object construct(Node node) { + Object result = null; + Class<? extends Object> customTag = typeTags.get(node.getTag()); + try { + Class cl; + if (customTag == null) { + if (node.getTag().length() < "tag:yaml.org,2002:".length()) { + throw new YAMLException("Unknown tag: " + node.getTag()); + } + String name = node.getTag().substring("tag:yaml.org,2002:".length()); + cl = Class.forName(name); + } else { + cl = customTag; + } + java.lang.reflect.Constructor javaConstructor; + switch (node.getNodeId()) { + case mapping: + MappingNode mnode = (MappingNode) node; + mnode.setType(cl); + result = constructMappingNode(mnode); + break; + case sequence: + SequenceNode seqNode = (SequenceNode) node; + List<Object> values = (List<Object>) constructSequence(seqNode); + Class[] parameterTypes = new Class[values.size()]; + int index = 0; + for (Object parameter : values) { + parameterTypes[index] = parameter.getClass(); + index++; + } + javaConstructor = cl.getConstructor(parameterTypes); + Object[] initargs = values.toArray(); + result = javaConstructor.newInstance(initargs); + break; + default:// scalar + ScalarNode scaNode = (ScalarNode) node; + Object value = constructScalar(scaNode); + if (Enum.class.isAssignableFrom(cl)) { + String enumValueName = (String) node.getValue(); + try { + result = Enum.valueOf(cl, enumValueName); + } catch (Exception ex) { + throw new YAMLException("Unable to find enum value '" + enumValueName + + "' for enum class: " + cl.getName()); + } + } else { + javaConstructor = cl.getConstructor(value.getClass()); + result = javaConstructor.newInstance(value); + } + } + } catch (Exception e) { + throw new ConstructorException(null, null, "Can't construct a java object for " + + node.getTag() + "; exception=" + e.getMessage(), node.getStartMark()); + } + return result; + } + } + + @Override + protected Object callConstructor(Node node) { + if (Object.class.equals(node.getType())) { + return super.callConstructor(node); + } + Object result; + switch (node.getNodeId()) { + case scalar: + result = constructScalarNode((ScalarNode) node); + break; + case sequence: + result = constructSequence((SequenceNode) node); + break; + default:// mapping + if (Map.class.isAssignableFrom(node.getType())) { + result = super.constructMapping((MappingNode) node); + } else { + result = constructMappingNode((MappingNode) node); + } + } + return result; + } + + private Object constructScalarNode(ScalarNode node) { + Class<? extends Object> type = node.getType(); + Object result; + if (type.isPrimitive() || type == String.class || Number.class.isAssignableFrom(type) + || type == Boolean.class || type == Date.class || type == Character.class + || type == BigInteger.class || Enum.class.isAssignableFrom(type)) { + if (type == String.class) { + Construct stringContructor = yamlConstructors.get("tag:yaml.org,2002:str"); + result = stringContructor.construct((ScalarNode) node); + } else if (type == Boolean.class || type == Boolean.TYPE) { + Construct boolContructor = yamlConstructors.get("tag:yaml.org,2002:bool"); + result = boolContructor.construct((ScalarNode) node); + } else if (type == Character.class || type == Character.TYPE) { + Construct charContructor = yamlConstructors.get("tag:yaml.org,2002:str"); + String ch = (String) charContructor.construct((ScalarNode) node); + if (ch.length() != 1) { + throw new YAMLException("Invalid node Character: '" + ch + "'; length: " + + ch.length()); + } + result = new Character(ch.charAt(0)); + } else if (type == Date.class) { + Construct dateContructor = yamlConstructors.get("tag:yaml.org,2002:timestamp"); + result = dateContructor.construct((ScalarNode) node); + } else if (type == Float.class || type == Double.class || type == Float.TYPE + || type == Double.TYPE) { + Construct doubleContructor = yamlConstructors.get("tag:yaml.org,2002:float"); + result = doubleContructor.construct(node); + if (type == Float.class || type == Float.TYPE) { + result = new Float((Double) result); + } + } else if (Number.class.isAssignableFrom(type) || type == Byte.TYPE + || type == Short.TYPE || type == Integer.TYPE || type == Long.TYPE) { + Construct intContructor = yamlConstructors.get("tag:yaml.org,2002:int"); + result = intContructor.construct(node); + if (type == Byte.class || type == Byte.TYPE) { + result = new Byte(result.toString()); + } else if (type == Short.class || type == Short.TYPE) { + result = new Short(result.toString()); + } else if (type == Integer.class || type == Integer.TYPE) { + result = new Integer(result.toString()); + } else if (type == Long.class || type == Long.TYPE) { + result = new Long(result.toString()); + } else if (type == BigInteger.class) { + result = new BigInteger(result.toString()); + } else { + throw new YAMLException("Unsupported Number class: " + type); + } + } else if (Enum.class.isAssignableFrom(type)) { + String tag = "tag:yaml.org,2002:" + type.getName(); + node.setTag(tag); + result = super.callConstructor(node); + } else { + throw new YAMLException("Unsupported class: " + type); + } + } else { + try { + // get value by BaseConstructor + Object value = super.callConstructor(node); + if (type.isArray()) { + result = value; + } else { + java.lang.reflect.Constructor<? extends Object> javaConstructor = type + .getConstructor(value.getClass()); + result = javaConstructor.newInstance(value); + } + } catch (Exception e) { + throw new YAMLException(e); + } + } + return result; + } + + /** + * Construct JavaBean. If type safe collections are used please look at + * <code>TypeDescription</code>. + * + * @param node + * - node where the keys are property names (they can only be + * <code>String</code>s) and values are objects to be created + * @return constructed JavaBean + */ + @SuppressWarnings("unchecked") + private Object constructMappingNode(MappingNode node) { + Class<? extends Object> beanType = node.getType(); + Object object; + try { + object = beanType.newInstance(); + } catch (InstantiationException e) { + throw new YAMLException(e); + } catch (IllegalAccessException e) { + throw new YAMLException(e); + } + List<Node[]> nodeValue = (List<Node[]>) node.getValue(); + for (Node[] tuple : nodeValue) { + ScalarNode keyNode; + if (tuple[0] instanceof ScalarNode) { + keyNode = (ScalarNode) tuple[0];// key must be scalar + } else { + throw new YAMLException("Keys must be scalars but found: " + tuple[0]); + } + Node valueNode = tuple[1]; + // keys can only be Strings + keyNode.setType(String.class); + String key = (String) constructObject(keyNode); + boolean isArray = false; + try { + Property property = getProperty(beanType, key); + if (property == null) + throw new YAMLException("Unable to find property '" + key + "' on class: " + + beanType.getName()); + valueNode.setType(property.getType()); + TypeDescription memberDescription = typeDefinitions.get(beanType); + if (memberDescription != null) { + switch (valueNode.getNodeId()) { + case sequence: + SequenceNode snode = (SequenceNode) valueNode; + Class<? extends Object> memberType = memberDescription + .getListPropertyType(key); + if (memberType != null) { + snode.setListType(memberType); + } else if (property.getType().isArray()) { + isArray = true; + snode.setListType(property.getType().getComponentType()); + } + break; + case mapping: + MappingNode mnode = (MappingNode) valueNode; + Class<? extends Object> keyType = memberDescription.getMapKeyType(key); + if (keyType != null) { + mnode.setKeyType(keyType); + mnode.setValueType(memberDescription.getMapValueType(key)); + } + break; + } + } + Object value = constructObject(valueNode); + if (isArray) { + List<Object> list = (List<Object>) value; + value = list.toArray(createArray(property.getType())); + } + property.set(object, value); + } catch (Exception e) { + throw new YAMLException(e); + } + } + return object; + } + + @SuppressWarnings("unchecked") + private <T> T[] createArray(Class<T> type) { + return (T[]) Array.newInstance(type.getComponentType(), 0); + } + + protected Property getProperty(Class<? extends Object> type, String name) + throws IntrospectionException { + for (PropertyDescriptor property : Introspector.getBeanInfo(type).getPropertyDescriptors()) { + if (property.getName().equals(name)) { + if (property.getReadMethod() != null && property.getWriteMethod() != null) + return new MethodProperty(property); + break; + } + } + for (Field field : type.getFields()) { + int modifiers = field.getModifiers(); + if (!Modifier.isPublic(modifiers) || Modifier.isStatic(modifiers) + || Modifier.isTransient(modifiers)) + continue; + if (field.getName().equals(name)) + return new FieldProperty(field); + } + return null; + } +} diff --git a/src/main/java/org/yaml/snakeyaml/constructor/ConstructorException.java b/src/main/java/org/yaml/snakeyaml/constructor/ConstructorException.java new file mode 100644 index 00000000..59f952e1 --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/constructor/ConstructorException.java @@ -0,0 +1,19 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.constructor; + +import org.yaml.snakeyaml.error.Mark; +import org.yaml.snakeyaml.error.MarkedYAMLException; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public class ConstructorException extends MarkedYAMLException { + private static final long serialVersionUID = -8816339931365239910L; + + protected ConstructorException(String context, Mark contextMark, String problem, + Mark problemMark) { + super(context, contextMark, problem, problemMark); + } +} diff --git a/src/main/java/org/yaml/snakeyaml/constructor/SafeConstructor.java b/src/main/java/org/yaml/snakeyaml/constructor/SafeConstructor.java new file mode 100644 index 00000000..c5de5cc1 --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/constructor/SafeConstructor.java @@ -0,0 +1,402 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.constructor;
+
+import java.math.BigInteger;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.TimeZone;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.yaml.snakeyaml.error.YAMLException;
+import org.yaml.snakeyaml.nodes.MappingNode;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.ScalarNode;
+import org.yaml.snakeyaml.nodes.SequenceNode;
+import org.yaml.snakeyaml.util.Base64Coder;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public class SafeConstructor extends BaseConstructor {
+
+ public SafeConstructor() {
+ this.yamlConstructors.put("tag:yaml.org,2002:null", new ConstuctYamlNull());
+ this.yamlConstructors.put("tag:yaml.org,2002:bool", new ConstuctYamlBool());
+ this.yamlConstructors.put("tag:yaml.org,2002:int", new ConstuctYamlInt());
+ this.yamlConstructors.put("tag:yaml.org,2002:float", new ConstuctYamlFloat());
+ this.yamlConstructors.put("tag:yaml.org,2002:binary", new ConstuctYamlBinary());
+ this.yamlConstructors.put("tag:yaml.org,2002:timestamp", new ConstuctYamlTimestamp());
+ this.yamlConstructors.put("tag:yaml.org,2002:omap", new ConstuctYamlOmap());
+ this.yamlConstructors.put("tag:yaml.org,2002:pairs", new ConstuctYamlPairs());
+ this.yamlConstructors.put("tag:yaml.org,2002:set", new ConstuctYamlSet());
+ this.yamlConstructors.put("tag:yaml.org,2002:str", new ConstuctYamlStr());
+ this.yamlConstructors.put("tag:yaml.org,2002:seq", new ConstuctYamlSeq());
+ this.yamlConstructors.put("tag:yaml.org,2002:map", new ConstuctYamlMap());
+ this.yamlConstructors.put(null, new ConstuctUndefined());
+ }
+
+ private void flattenMapping(MappingNode node) {
+ List<Node[]> merge = new LinkedList<Node[]>();
+ int index = 0;
+ List<Node[]> nodeValue = (List<Node[]>) node.getValue();
+ while (index < nodeValue.size()) {
+ Node keyNode = nodeValue.get(index)[0];
+ Node valueNode = nodeValue.get(index)[1];
+ if (keyNode.getTag().equals("tag:yaml.org,2002:merge")) {
+ nodeValue.remove(index);
+ switch (valueNode.getNodeId()) {
+ case mapping:
+ MappingNode mn = (MappingNode) valueNode;
+ flattenMapping(mn);
+ merge.addAll(mn.getValue());
+ break;
+ case sequence:
+ List<List<Node[]>> submerge = new LinkedList<List<Node[]>>();
+ SequenceNode sn = (SequenceNode) valueNode;
+ List<Node> vals = sn.getValue();
+ for (Node subnode : vals) {
+ if (!(subnode instanceof MappingNode)) {
+ throw new ConstructorException("while constructing a mapping", node
+ .getStartMark(), "expected a mapping for merging, but found "
+ + subnode.getNodeId(), subnode.getStartMark());
+ }
+ MappingNode mnode = (MappingNode) subnode;
+ flattenMapping(mnode);
+ submerge.add(mnode.getValue());
+ }
+ Collections.reverse(submerge);
+ for (List<Node[]> value : submerge) {
+ merge.addAll(value);
+ }
+ break;
+ default:
+ throw new ConstructorException("while constructing a mapping", node
+ .getStartMark(),
+ "expected a mapping or list of mappings for merging, but found "
+ + valueNode.getNodeId(), valueNode.getStartMark());
+ }
+ } else if (keyNode.getTag().equals("tag:yaml.org,2002:value")) {
+ keyNode.setTag("tag:yaml.org,2002:str");
+ index++;
+ } else {
+ index++;
+ }
+ }
+ if (!merge.isEmpty()) {
+ merge.addAll(nodeValue);
+ ((MappingNode) node).setValue(merge);
+ }
+ }
+
+ protected Map<Object, Object> constructMapping(MappingNode node) {
+ flattenMapping(node);
+ return super.constructMapping(node);
+ }
+
+ private class ConstuctYamlNull implements Construct {
+ public Object construct(Node node) {
+ constructScalar((ScalarNode) node);
+ return null;
+ }
+ }
+
+ private final static Map<String, Boolean> BOOL_VALUES = new HashMap<String, Boolean>();
+ static {
+ BOOL_VALUES.put("yes", Boolean.TRUE);
+ BOOL_VALUES.put("no", Boolean.FALSE);
+ BOOL_VALUES.put("true", Boolean.TRUE);
+ BOOL_VALUES.put("false", Boolean.FALSE);
+ BOOL_VALUES.put("on", Boolean.TRUE);
+ BOOL_VALUES.put("off", Boolean.FALSE);
+ }
+
+ private class ConstuctYamlBool implements Construct {
+ public Object construct(Node node) {
+ String val = (String) constructScalar((ScalarNode) node);
+ return BOOL_VALUES.get(val.toLowerCase());
+ }
+ }
+
+ private class ConstuctYamlInt implements Construct {
+ public Object construct(Node node) {
+ String value = constructScalar((ScalarNode) node).toString().replaceAll("_", "");
+ int sign = +1;
+ char first = value.charAt(0);
+ if (first == '-') {
+ sign = -1;
+ value = value.substring(1);
+ } else if (first == '+') {
+ value = value.substring(1);
+ }
+ int base = 10;
+ if (value.equals("0")) {
+ return new Integer(0);
+ } else if (value.startsWith("0b")) {
+ value = value.substring(2);
+ base = 2;
+ } else if (value.startsWith("0x")) {
+ value = value.substring(2);
+ base = 16;
+ } else if (value.startsWith("0")) {
+ value = value.substring(1);
+ base = 8;
+ } else if (value.indexOf(':') != -1) {
+ String[] digits = value.split(":");
+ int bes = 1;
+ int val = 0;
+ for (int i = 0, j = digits.length; i < j; i++) {
+ val += (Long.parseLong(digits[(j - i) - 1]) * bes);
+ bes *= 60;
+ }
+ return createNumber(sign, String.valueOf(val), 10);
+ } else {
+ return createNumber(sign, value, 10);
+ }
+ return createNumber(sign, value, base);
+ }
+ }
+
+ private Number createNumber(int sign, String number, int radix) {
+ Number result;
+ if (sign < 0) {
+ number = "-" + number;
+ }
+ try {
+ int integer = Integer.parseInt(number, radix);
+ result = new Integer(integer);
+ } catch (NumberFormatException e) {
+ try {
+ long longValue = Long.parseLong(number, radix);
+ result = new Long(longValue);
+ } catch (NumberFormatException e1) {
+ result = new BigInteger(number, radix);
+ }
+ }
+ return result;
+ }
+
+ private class ConstuctYamlFloat implements Construct {
+ public Object construct(Node node) {
+ String value = constructScalar((ScalarNode) node).toString().replaceAll("_", "");
+ int sign = +1;
+ char first = value.charAt(0);
+ if (first == '-') {
+ sign = -1;
+ value = value.substring(1);
+ } else if (first == '+') {
+ value = value.substring(1);
+ }
+ String valLower = value.toLowerCase();
+ if (valLower.equals(".inf")) {
+ return new Double(sign == -1 ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY);
+ } else if (valLower.equals(".nan")) {
+ return new Double(Double.NaN);
+ } else if (value.indexOf(':') != -1) {
+ String[] digits = value.split(":");
+ int bes = 1;
+ double val = 0.0;
+ for (int i = 0, j = digits.length; i < j; i++) {
+ val += (Double.parseDouble(digits[(j - i) - 1]) * bes);
+ bes *= 60;
+ }
+ return new Double(sign * val);
+ } else {
+ try {
+ Double d = Double.valueOf(value);
+ return new Double(d.doubleValue() * sign);
+ } catch (NumberFormatException e) {
+ throw new YAMLException("Invalid number: '" + value + "'; in node " + node);
+ }
+ }
+ }
+ }
+
+ private class ConstuctYamlBinary implements Construct {
+ public Object construct(Node node) {
+ byte[] decoded = Base64Coder.decode(constructScalar((ScalarNode) node).toString()
+ .toCharArray());
+ return decoded;
+ }
+ }
+
+ private final static Pattern TIMESTAMP_REGEXP = Pattern
+ .compile("^([0-9][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)(?:(?:[Tt]|[ \t]+)([0-9][0-9]?):([0-9][0-9]):([0-9][0-9])(?:\\.([0-9]*))?(?:[ \t]*(?:Z|([-+][0-9][0-9]?)(?::([0-9][0-9])?)?))?)?$");
+ private final static Pattern YMD_REGEXP = Pattern
+ .compile("^([0-9][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)$");
+
+ private class ConstuctYamlTimestamp implements Construct {
+ public Object construct(Node node) {
+ Matcher match = YMD_REGEXP.matcher((String) node.getValue());
+ if (match.matches()) {
+ String year_s = match.group(1);
+ String month_s = match.group(2);
+ String day_s = match.group(3);
+ Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
+ cal.clear();
+ cal.set(Calendar.YEAR, Integer.parseInt(year_s));
+ // Java's months are zero-based...
+ cal.set(Calendar.MONTH, Integer.parseInt(month_s) - 1); // x
+ cal.set(Calendar.DAY_OF_MONTH, Integer.parseInt(day_s));
+ return cal.getTime();
+ } else {
+ match = TIMESTAMP_REGEXP.matcher((String) node.getValue());
+ if (!match.matches()) {
+ throw new YAMLException("Expected timestamp: " + node);
+ }
+ String year_s = match.group(1);
+ String month_s = match.group(2);
+ String day_s = match.group(3);
+ String hour_s = match.group(4);
+ String min_s = match.group(5);
+ String sec_s = match.group(6);
+ String fract_s = match.group(7);
+ String timezoneh_s = match.group(8);
+ String timezonem_s = match.group(9);
+
+ int usec = 0;
+ if (fract_s != null) {
+ usec = Integer.parseInt(fract_s);
+ if (usec != 0) {
+ while (10 * usec < 1000) {
+ usec *= 10;
+ }
+ }
+ }
+ Calendar cal = Calendar.getInstance();
+ cal.set(Calendar.YEAR, Integer.parseInt(year_s));
+ // Java's months are zero-based...
+ cal.set(Calendar.MONTH, Integer.parseInt(month_s) - 1);
+ cal.set(Calendar.DAY_OF_MONTH, Integer.parseInt(day_s));
+ cal.set(Calendar.HOUR_OF_DAY, Integer.parseInt(hour_s));
+ cal.set(Calendar.MINUTE, Integer.parseInt(min_s));
+ cal.set(Calendar.SECOND, Integer.parseInt(sec_s));
+ cal.set(Calendar.MILLISECOND, usec);
+ if (timezoneh_s != null || timezonem_s != null) {
+ int zone = 0;
+ int sign = +1;
+ if (timezoneh_s != null) {
+ if (timezoneh_s.startsWith("-")) {
+ sign = -1;
+ }
+ zone += Integer.parseInt(timezoneh_s.substring(1)) * 3600000;
+ }
+ if (timezonem_s != null) {
+ zone += Integer.parseInt(timezonem_s) * 60000;
+ }
+ cal.set(Calendar.ZONE_OFFSET, sign * zone);
+ } else {
+ cal.setTimeZone(TimeZone.getTimeZone("UTC"));
+ }
+ return cal.getTime();
+ }
+ }
+ }
+
+ private class ConstuctYamlOmap implements Construct {
+ public Object construct(Node node) {
+ // Note: we do not check for duplicate keys, because it's too
+ // CPU-expensive.
+ Map<Object, Object> omap = new LinkedHashMap<Object, Object>();
+ if (!(node instanceof SequenceNode)) {
+ throw new ConstructorException("while constructing an ordered map", node
+ .getStartMark(), "expected a sequence, but found " + node.getNodeId(), node
+ .getStartMark());
+ }
+ SequenceNode snode = (SequenceNode) node;
+ for (Node subnode : snode.getValue()) {
+ if (!(subnode instanceof MappingNode)) {
+ throw new ConstructorException("while constructing an ordered map", node
+ .getStartMark(), "expected a mapping of length 1, but found "
+ + subnode.getNodeId(), subnode.getStartMark());
+ }
+ MappingNode mnode = (MappingNode) subnode;
+ if (mnode.getValue().size() != 1) {
+ throw new ConstructorException("while constructing an ordered map", node
+ .getStartMark(), "expected a single mapping item, but found "
+ + mnode.getValue().size() + " items", mnode.getStartMark());
+ }
+ Node keyNode = mnode.getValue().get(0)[0];
+ Node valueNode = mnode.getValue().get(0)[1];
+ Object key = constructObject(keyNode);
+ Object value = constructObject(valueNode);
+ omap.put(key, value);
+ }
+ return omap;
+ }
+ }
+
+ // Note: the same code as `construct_yaml_omap`.
+ private class ConstuctYamlPairs implements Construct {
+ public Object construct(Node node) {
+ // Note: we do not check for duplicate keys, because it's too
+ // CPU-expensive.
+ List<Object[]> pairs = new LinkedList<Object[]>();
+ if (!(node instanceof SequenceNode)) {
+ throw new ConstructorException("while constructing pairs", node.getStartMark(),
+ "expected a sequence, but found " + node.getNodeId(), node.getStartMark());
+ }
+ SequenceNode snode = (SequenceNode) node;
+ for (Node subnode : snode.getValue()) {
+ if (!(subnode instanceof MappingNode)) {
+ throw new ConstructorException("while constructingpairs", node.getStartMark(),
+ "expected a mapping of length 1, but found " + subnode.getNodeId(),
+ subnode.getStartMark());
+ }
+ MappingNode mnode = (MappingNode) subnode;
+ if (mnode.getValue().size() != 1) {
+ throw new ConstructorException("while constructing pairs", node.getStartMark(),
+ "expected a single mapping item, but found " + mnode.getValue().size()
+ + " items", mnode.getStartMark());
+ }
+ Node keyNode = mnode.getValue().get(0)[0];
+ Node valueNode = mnode.getValue().get(0)[1];
+ Object key = constructObject(keyNode);
+ Object value = constructObject(valueNode);
+ pairs.add(new Object[] { key, value });
+ }
+ return pairs;
+ }
+ }
+
+ private class ConstuctYamlSet implements Construct {
+ public Object construct(Node node) {
+ Map<Object, Object> value = constructMapping((MappingNode) node);
+ return value.keySet();
+ }
+ }
+
+ private class ConstuctYamlStr implements Construct {
+ public Object construct(Node node) {
+ String value = (String) constructScalar((ScalarNode) node);
+ return value;
+ }
+ }
+
+ private class ConstuctYamlSeq implements Construct {
+ public Object construct(Node node) {
+ return constructSequence((SequenceNode) node);
+ }
+ }
+
+ private class ConstuctYamlMap implements Construct {
+ public Object construct(Node node) {
+ return constructMapping((MappingNode) node);
+ }
+ }
+
+ private class ConstuctUndefined implements Construct {
+ public Object construct(Node node) {
+ throw new ConstructorException(null, null,
+ "could not determine a constructor for the tag " + node.getTag(), node
+ .getStartMark());
+ }
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/emitter/Emitter.java b/src/main/java/org/yaml/snakeyaml/emitter/Emitter.java new file mode 100644 index 00000000..36b62e92 --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/emitter/Emitter.java @@ -0,0 +1,1422 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.emitter; + +import java.io.IOException; +import java.io.Writer; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.Map; +import java.util.Queue; +import java.util.Set; +import java.util.TreeSet; +import java.util.regex.Pattern; + +import org.yaml.snakeyaml.DumperOptions; +import org.yaml.snakeyaml.events.AliasEvent; +import org.yaml.snakeyaml.events.CollectionEndEvent; +import org.yaml.snakeyaml.events.CollectionStartEvent; +import org.yaml.snakeyaml.events.DocumentEndEvent; +import org.yaml.snakeyaml.events.DocumentStartEvent; +import org.yaml.snakeyaml.events.Event; +import org.yaml.snakeyaml.events.MappingEndEvent; +import org.yaml.snakeyaml.events.MappingStartEvent; +import org.yaml.snakeyaml.events.NodeEvent; +import org.yaml.snakeyaml.events.ScalarEvent; +import org.yaml.snakeyaml.events.SequenceEndEvent; +import org.yaml.snakeyaml.events.SequenceStartEvent; +import org.yaml.snakeyaml.events.StreamEndEvent; +import org.yaml.snakeyaml.events.StreamStartEvent; + +/** + * <pre> + * Emitter expects events obeying the following grammar: + * stream ::= STREAM-START document* STREAM-END + * document ::= DOCUMENT-START node DOCUMENT-END + * node ::= SCALAR | sequence | mapping + * sequence ::= SEQUENCE-START node* SEQUENCE-END + * mapping ::= MAPPING-START (node node)* MAPPING-END + * </pre> + * + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public final class Emitter { + private static final Map<Character, String> ESCAPE_REPLACEMENTS = new HashMap<Character, String>(); + public static final int MIN_INDENT = 1; + public static final int MAX_INDENT = 10; + + static { + ESCAPE_REPLACEMENTS.put(new Character('\0'), "0"); + ESCAPE_REPLACEMENTS.put(new Character('\u0007'), "a"); + ESCAPE_REPLACEMENTS.put(new Character('\u0008'), "b"); + ESCAPE_REPLACEMENTS.put(new Character('\u0009'), "t"); + ESCAPE_REPLACEMENTS.put(new Character('\n'), "n"); + ESCAPE_REPLACEMENTS.put(new Character('\u000B'), "v"); + ESCAPE_REPLACEMENTS.put(new Character('\u000C'), "f"); + ESCAPE_REPLACEMENTS.put(new Character('\r'), "r"); + ESCAPE_REPLACEMENTS.put(new Character('\u001B'), "e"); + ESCAPE_REPLACEMENTS.put(new Character('"'), "\""); + ESCAPE_REPLACEMENTS.put(new Character('\\'), "\\"); + ESCAPE_REPLACEMENTS.put(new Character('\u0085'), "N"); + ESCAPE_REPLACEMENTS.put(new Character('\u00A0'), "_"); + ESCAPE_REPLACEMENTS.put(new Character('\u2028'), "L"); + ESCAPE_REPLACEMENTS.put(new Character('\u2029'), "P"); + } + + private final static Map<String, String> DEFAULT_TAG_PREFIXES = new LinkedHashMap<String, String>(); + static { + DEFAULT_TAG_PREFIXES.put("!", "!"); + DEFAULT_TAG_PREFIXES.put("tag:yaml.org,2002:", "!!"); + } + // The stream should have the methods `write` and possibly `flush`. + private final Writer stream; + + // Encoding is defined by Writer (cannot be overriden by STREAM-START.) + // private Charset encoding; + + // Emitter is a state machine with a stack of states to handle nested + // structures. + private final LinkedList<EmitterState> states; + private EmitterState state; + + // Current event and the event queue. + private final Queue<Event> events; + private Event event; + + // The current indentation level and the stack of previous indents. + private final LinkedList<Integer> indents; + private Integer indent; + + // Flow level. + private int flowLevel; + + // Contexts. + private boolean rootContext; + private boolean mappingContext; + private boolean simpleKeyContext; + + // + // Characteristics of the last emitted character: + // - current position. + // - is it a whitespace? + // - is it an indention character + // (indentation space, '-', '?', or ':')? + private int line; + private int column; + private boolean whitespace; + private boolean indention; + private boolean openEnded; + + // Formatting details. + private Boolean canonical; + private boolean allowUnicode; + private int bestIndent; + private int bestWidth; + private String bestLineBreak; + + // Tag prefixes. + private Map<String, String> tagPrefixes; + + // Prepared anchor and tag. + private String preparedAnchor; + private String preparedTag; + + // Scalar analysis and style. + private ScalarAnalysis analysis; + private char style = 0; + + public Emitter(Writer stream, DumperOptions opts) { + // The stream should have the methods `write` and possibly `flush`. + this.stream = stream; + // Emitter is a state machine with a stack of states to handle nested + // structures. + this.states = new LinkedList<EmitterState>(); + this.state = new ExpectStreamStart(); + // Current event and the event queue. + this.events = new LinkedList<Event>(); + this.event = null; + // The current indentation level and the stack of previous indents. + this.indents = new LinkedList<Integer>(); + this.indent = null; + // Flow level. + this.flowLevel = 0; + // Contexts. + mappingContext = false; + simpleKeyContext = false; + + // + // Characteristics of the last emitted character: + // - current position. + // - is it a whitespace? + // - is it an indention character + // (indentation space, '-', '?', or ':')? + line = 0; + column = 0; + whitespace = true; + indention = true; + + // Whether the document requires an explicit document indicator + openEnded = false; + + // Formatting details. + this.canonical = opts.isCanonical(); + this.allowUnicode = opts.isAllowUnicode(); + this.bestIndent = 2; + if ((opts.getIndent() > MIN_INDENT) && (opts.getIndent() < MAX_INDENT)) { + this.bestIndent = opts.getIndent(); + } + this.bestWidth = 80; + if (opts.getWidth() > this.bestIndent * 2) { + this.bestWidth = opts.getWidth(); + } + this.bestLineBreak = opts.getLineBreak().getString(); + + // Tag prefixes. + this.tagPrefixes = new LinkedHashMap<String, String>(); + + // Prepared anchor and tag. + this.preparedAnchor = null; + this.preparedTag = null; + + // Scalar analysis and style. + this.analysis = null; + this.style = (char) 0; + } + + public void emit(Event event) throws IOException { + this.events.offer(event); + while (!needMoreEvents()) { + this.event = this.events.poll(); + this.state.expect(); + this.event = null; + } + } + + // In some cases, we wait for a few next events before emitting. + + private boolean needMoreEvents() { + if (events.isEmpty()) { + return true; + } + Event event = events.peek(); + if (event instanceof DocumentStartEvent) { + return needEvents(1); + } else if (event instanceof SequenceStartEvent) { + return needEvents(2); + } else if (event instanceof MappingStartEvent) { + return needEvents(3); + } else { + return false; + } + } + + private boolean needEvents(int count) { + int level = 0; + Iterator<Event> iter = events.iterator(); + iter.next(); + while (iter.hasNext()) { + Event event = iter.next(); + if (event instanceof DocumentStartEvent || event instanceof CollectionStartEvent) { + level++; + } else if (event instanceof DocumentEndEvent || event instanceof CollectionEndEvent) { + level--; + } else if (event instanceof StreamEndEvent) { + level = -1; + } + if (level < 0) { + return false; + } + } + return events.size() < count + 1; + } + + private void increaseIndent(boolean flow, boolean indentless) { + indents.addFirst(indent); + if (indent == null) { + if (flow) { + indent = bestIndent; + } else { + indent = 0; + } + } else if (!indentless) { + this.indent += bestIndent; + } + } + + // States + + // Stream handlers. + + private class ExpectStreamStart implements EmitterState { + public void expect() throws IOException { + if (event instanceof StreamStartEvent) { + writeStreamStart(); + state = new ExpectFirstDocumentStart(); + } else { + throw new EmitterException("expected StreamStartEvent, but got " + event); + } + } + } + + private class ExpectNothing implements EmitterState { + public void expect() throws IOException { + throw new EmitterException("expecting nothing, but got " + event); + } + } + + // Document handlers. + + private class ExpectFirstDocumentStart implements EmitterState { + public void expect() throws IOException { + new ExpectDocumentStart(true).expect(); + } + } + + private class ExpectDocumentStart implements EmitterState { + private boolean first; + + public ExpectDocumentStart(boolean first) { + this.first = first; + } + + public void expect() throws IOException { + if (event instanceof DocumentStartEvent) { + DocumentStartEvent ev = (DocumentStartEvent) event; + if ((ev.getVersion() != null || ev.getTags() != null) && openEnded) { + writeIndicator("...", true, false, false); + writeIndent(); + } + if (ev.getVersion() != null) { + String versionText = prepareVersion(ev.getVersion()); + writeVersionDirective(versionText); + } + tagPrefixes = new LinkedHashMap<String, String>(DEFAULT_TAG_PREFIXES); + if (ev.getTags() != null) { + Set<String> handles = new TreeSet<String>(ev.getTags().keySet()); + for (String handle : handles) { + String prefix = ev.getTags().get(handle); + tagPrefixes.put(prefix, handle); + String handleText = prepareTagHandle(handle); + String prefixText = prepareTagPrefix(prefix); + writeTagDirective(handleText, prefixText); + } + } + boolean implicit = first && !ev.getExplicit() && !canonical + && ev.getVersion() == null && ev.getTags() == null && !checkEmptyDocument(); + if (!implicit) { + writeIndent(); + writeIndicator("---", true, false, false); + if (canonical) { + writeIndent(); + } + } + state = new ExpectDocumentRoot(); + } else if (event instanceof StreamEndEvent) { + // TODO fix 313 PyYAML changeset + // if (openEnded) { + // writeIndicator("...", true, false, false); + // writeIndent(); + // } + writeStreamEnd(); + state = new ExpectNothing(); + } else { + throw new EmitterException("expected DocumentStartEvent, but got " + event); + } + } + } + + private class ExpectDocumentEnd implements EmitterState { + public void expect() throws IOException { + if (event instanceof DocumentEndEvent) { + writeIndent(); + if (((DocumentEndEvent) event).getExplicit()) { + writeIndicator("...", true, false, false); + writeIndent(); + } + flushStream(); + state = new ExpectDocumentStart(false); + } else { + throw new EmitterException("expected DocumentEndEvent, but got " + event); + } + } + } + + private class ExpectDocumentRoot implements EmitterState { + public void expect() throws IOException { + states.addFirst(new ExpectDocumentEnd()); + expectNode(true, false, false, false); + } + } + + // Node handlers. + + private void expectNode(boolean root, boolean sequence, boolean mapping, boolean simpleKey) + throws IOException { + rootContext = root; + mappingContext = mapping; + simpleKeyContext = simpleKey; + if (event instanceof AliasEvent) { + expectAlias(); + } else if (event instanceof ScalarEvent || event instanceof CollectionStartEvent) { + processAnchor("&"); + processTag(); + if (event instanceof ScalarEvent) { + expectScalar(); + } else if (event instanceof SequenceStartEvent) { + if (flowLevel != 0 || canonical || ((SequenceStartEvent) event).getFlowStyle() + || checkEmptySequence()) { + expectFlowSequence(); + } else { + expectBlockSequence(); + } + } else {// MappingStartEvent + if (flowLevel != 0 || canonical || ((MappingStartEvent) event).getFlowStyle() + || checkEmptyMapping()) { + expectFlowMapping(); + } else { + expectBlockMapping(); + } + } + } else { + throw new EmitterException("expected NodeEvent, but got " + event); + } + } + + private void expectAlias() throws IOException { + if (((NodeEvent) event).getAnchor() == null) { + throw new EmitterException("anchor is not specified for alias"); + } + processAnchor("*"); + state = states.removeFirst(); + } + + private void expectScalar() throws IOException { + increaseIndent(true, false); + processScalar(); + indent = indents.removeFirst(); + state = states.removeFirst(); + } + + // Flow sequence handlers. + + private void expectFlowSequence() throws IOException { + writeIndicator("[", true, true, false); + flowLevel++; + increaseIndent(true, false); + state = new ExpectFirstFlowSequenceItem(); + } + + private class ExpectFirstFlowSequenceItem implements EmitterState { + public void expect() throws IOException { + if (event instanceof SequenceEndEvent) { + indent = indents.removeFirst(); + flowLevel--; + writeIndicator("]", false, false, false); + state = states.removeFirst(); + } else { + if (canonical || column > bestWidth) { + writeIndent(); + } + states.addFirst(new ExpectFlowSequenceItem()); + expectNode(false, true, false, false); + } + } + } + + private class ExpectFlowSequenceItem implements EmitterState { + public void expect() throws IOException { + if (event instanceof SequenceEndEvent) { + indent = indents.removeFirst(); + flowLevel--; + if (canonical) { + writeIndicator(",", false, false, false); + writeIndent(); + } + writeIndicator("]", false, false, false); + state = states.removeFirst(); + } else { + writeIndicator(",", false, false, false); + if (canonical || column > bestWidth) { + writeIndent(); + } + states.addFirst(new ExpectFlowSequenceItem()); + expectNode(false, true, false, false); + } + } + } + + // Flow mapping handlers. + + private void expectFlowMapping() throws IOException { + writeIndicator("{", true, true, false); + flowLevel++; + increaseIndent(true, false); + state = new ExpectFirstFlowMappingKey(); + } + + private class ExpectFirstFlowMappingKey implements EmitterState { + public void expect() throws IOException { + if (event instanceof MappingEndEvent) { + indent = indents.removeFirst(); + flowLevel--; + writeIndicator("}", false, false, false); + state = states.removeFirst(); + } else { + if (canonical || column > bestWidth) { + writeIndent(); + } + if (!canonical && checkSimpleKey()) { + states.addFirst(new ExpectFlowMappingSimpleValue()); + expectNode(false, false, true, true); + } else { + writeIndicator("?", true, false, false); + states.addFirst(new ExpectFlowMappingValue()); + expectNode(false, false, true, false); + } + } + } + } + + private class ExpectFlowMappingKey implements EmitterState { + public void expect() throws IOException { + if (event instanceof MappingEndEvent) { + indent = indents.removeFirst(); + flowLevel--; + if (canonical) { + writeIndicator(",", false, false, false); + writeIndent(); + } + writeIndicator("}", false, false, false); + state = states.removeFirst(); + } else { + writeIndicator(",", false, false, false); + if (canonical || column > bestWidth) { + writeIndent(); + } + if (!canonical && checkSimpleKey()) { + states.addFirst(new ExpectFlowMappingSimpleValue()); + expectNode(false, false, true, true); + } else { + writeIndicator("?", true, false, false); + states.addFirst(new ExpectFlowMappingValue()); + expectNode(false, false, true, false); + } + } + } + } + + private class ExpectFlowMappingSimpleValue implements EmitterState { + public void expect() throws IOException { + writeIndicator(":", false, false, false); + states.addFirst(new ExpectFlowMappingKey()); + expectNode(false, false, true, false); + } + } + + private class ExpectFlowMappingValue implements EmitterState { + public void expect() throws IOException { + if (canonical || column > bestWidth) { + writeIndent(); + } + writeIndicator(":", true, false, false); + states.addFirst(new ExpectFlowMappingKey()); + expectNode(false, false, true, false); + } + } + + // Block sequence handlers. + + private void expectBlockSequence() throws IOException { + boolean indentless = (mappingContext && !indention); + increaseIndent(false, indentless); + state = new ExpectFirstBlockSequenceItem(); + } + + private class ExpectFirstBlockSequenceItem implements EmitterState { + public void expect() throws IOException { + new ExpectBlockSequenceItem(true).expect(); + } + } + + private class ExpectBlockSequenceItem implements EmitterState { + private boolean first; + + public ExpectBlockSequenceItem(boolean first) { + this.first = first; + } + + public void expect() throws IOException { + if (!this.first && event instanceof SequenceEndEvent) { + indent = indents.removeFirst(); + state = states.removeFirst(); + } else { + writeIndent(); + writeIndicator("-", true, false, true); + states.addFirst(new ExpectBlockSequenceItem(false)); + expectNode(false, true, false, false); + } + } + } + + // Block mapping handlers. + private void expectBlockMapping() throws IOException { + increaseIndent(false, false); + state = new ExpectFirstBlockMappingKey(); + } + + private class ExpectFirstBlockMappingKey implements EmitterState { + public void expect() throws IOException { + new ExpectBlockMappingKey(true).expect(); + } + } + + private class ExpectBlockMappingKey implements EmitterState { + private boolean first; + + public ExpectBlockMappingKey(boolean first) { + this.first = first; + } + + public void expect() throws IOException { + if (!this.first && event instanceof MappingEndEvent) { + indent = indents.removeFirst(); + state = states.removeFirst(); + } else { + writeIndent(); + if (checkSimpleKey()) { + states.addFirst(new ExpectBlockMappingSimpleValue()); + expectNode(false, false, true, true); + } else { + writeIndicator("?", true, false, true); + states.addFirst(new ExpectBlockMappingValue()); + expectNode(false, false, true, false); + } + } + } + } + + private class ExpectBlockMappingSimpleValue implements EmitterState { + public void expect() throws IOException { + writeIndicator(":", false, false, false); + states.addFirst(new ExpectBlockMappingKey(false)); + expectNode(false, false, true, false); + } + } + + private class ExpectBlockMappingValue implements EmitterState { + public void expect() throws IOException { + writeIndent(); + writeIndicator(":", true, false, true); + states.addFirst(new ExpectBlockMappingKey(false)); + expectNode(false, false, true, false); + } + } + + // Checkers. + + private boolean checkEmptySequence() { + return (event instanceof SequenceStartEvent && !events.isEmpty() && events.peek() instanceof SequenceEndEvent); + } + + private boolean checkEmptyMapping() { + return (event instanceof MappingStartEvent && !events.isEmpty() && events.peek() instanceof MappingEndEvent); + } + + private boolean checkEmptyDocument() { + if (!(event instanceof DocumentStartEvent) || events.isEmpty()) { + return false; + } + Event event = events.peek(); + if (event instanceof ScalarEvent) { + ScalarEvent e = (ScalarEvent) event; + return (e.getAnchor() == null && e.getTag() == null && e.getImplicit() != null && e + .getValue() == ""); + } else { + return false; + } + } + + private boolean checkSimpleKey() { + int length = 0; + if (event instanceof NodeEvent && ((NodeEvent) event).getAnchor() != null) { + if (preparedAnchor == null) { + preparedAnchor = prepareAnchor(((NodeEvent) event).getAnchor()); + } + length += preparedAnchor.length(); + } + String tag = null; + if (event instanceof ScalarEvent) { + tag = ((ScalarEvent) event).getTag(); + } else if (event instanceof CollectionStartEvent) { + tag = ((CollectionStartEvent) event).getTag(); + } + if (tag != null) { + if (preparedTag == null) { + preparedTag = prepareTag(tag); + } + length += preparedTag.length(); + } + if (event instanceof ScalarEvent) { + if (analysis == null) { + analysis = analyzeScalar(((ScalarEvent) event).getValue()); + } + length += analysis.scalar.length(); + } + return (length < 128 && (event instanceof AliasEvent + || (event instanceof ScalarEvent && !analysis.empty && !analysis.multiline) + || checkEmptySequence() || checkEmptyMapping())); + } + + // Anchor, Tag, and Scalar processors. + + private void processAnchor(String indicator) throws IOException { + NodeEvent ev = (NodeEvent) event; + if (ev.getAnchor() == null) { + preparedAnchor = null; + return; + } + if (preparedAnchor == null) { + preparedAnchor = prepareAnchor(ev.getAnchor()); + } + if (preparedAnchor != null && !"".equals(preparedAnchor)) { + writeIndicator(indicator + preparedAnchor, true, false, false); + } + preparedAnchor = null; + } + + private void processTag() throws IOException { + String tag = null; + if (event instanceof ScalarEvent) { + ScalarEvent ev = (ScalarEvent) event; + tag = ev.getTag(); + if (style == 0) { + style = chooseScalarStyle(); + } + if (((!canonical || tag == null) && ((style == 0 && ev.getImplicit()[0]) || (style != 0 && ev + .getImplicit()[1])))) { + preparedTag = null; + return; + } + if (ev.getImplicit()[0] && tag == null) { + tag = "!"; + preparedTag = null; + } + } else { + CollectionStartEvent ev = (CollectionStartEvent) event; + tag = ev.getTag(); + if ((!canonical || tag == null) && ev.getImplicit()) { + preparedTag = null; + return; + } + } + if (tag == null) { + throw new EmitterException("tag is not specified"); + } + if (preparedTag == null) { + preparedTag = prepareTag(tag); + } + if (preparedTag != null && !"".equals(preparedTag)) { + writeIndicator(preparedTag, true, false, false); + } + preparedTag = null; + } + + private char chooseScalarStyle() { + ScalarEvent ev = (ScalarEvent) event; + if (analysis == null) { + analysis = analyzeScalar(ev.getValue()); + } + if (ev.getStyle() != null && ev.getStyle() == '"' || this.canonical) { + return '"'; + } + if (ev.getStyle() == null && ev.getImplicit()[0]) { + if (!(simpleKeyContext && (analysis.empty || analysis.multiline)) + && ((flowLevel != 0 && analysis.allowFlowPlain) || (flowLevel == 0 && analysis.allowBlockPlain))) { + return 0; + } + } + if (ev.getStyle() != null && (ev.getStyle() == '|' || ev.getStyle() == '>')) { + if (flowLevel == 0 && !simpleKeyContext && analysis.allowBlock) { + return ev.getStyle(); + } + } + if (ev.getStyle() == null || ev.getStyle() == '\'') { + if (analysis.allowSingleQuoted && !(simpleKeyContext && analysis.multiline)) { + return '\''; + } + } + return '"'; + } + + private void processScalar() throws IOException { + ScalarEvent ev = (ScalarEvent) event; + if (analysis == null) { + analysis = analyzeScalar(ev.getValue()); + } + if (style == 0) { + style = chooseScalarStyle(); + } + boolean split = !simpleKeyContext; + if (style == '"') { + writeDoubleQuoted(analysis.scalar, split); + } else if (style == '\'') { + writeSingleQuoted(analysis.scalar, split); + } else if (style == '>') { + writeFolded(analysis.scalar); + } else if (style == '|') { + writeLiteral(analysis.scalar); + } else { + writePlain(analysis.scalar, split); + } + analysis = null; + style = 0; + } + + // Analyzers. + + private String prepareVersion(Integer[] version) { + Integer major = version[0]; + Integer minor = version[1]; + if (major != 1) { + throw new EmitterException("unsupported YAML version: " + version[0] + "." + version[1]); + } + return major.toString() + "." + minor.toString(); + } + + private final static Pattern HANDLE_FORMAT = Pattern.compile("^![-_\\w]*!$"); + + private String prepareTagHandle(String handle) { + if (handle == null || "".equals(handle)) { + throw new EmitterException("tag handle must not be empty"); + } else if (handle.charAt(0) != '!' || handle.charAt(handle.length() - 1) != '!') { + throw new EmitterException("tag handle must start and end with '!': " + handle); + } else if (!"!".equals(handle) && !HANDLE_FORMAT.matcher(handle).matches()) { + throw new EmitterException("invalid character in the tag handle: " + handle); + } + return handle; + } + + private String prepareTagPrefix(String prefix) { + if (prefix == null || "".equals(prefix)) { + throw new EmitterException("tag prefix must not be empty"); + } + StringBuffer chunks = new StringBuffer(); + int start = 0; + int end = 0; + if (prefix.charAt(0) == '!') { + end = 1; + } + while (end < prefix.length()) { + end++; + } + if (start < end) { + chunks.append(prefix.substring(start, end)); + } + return chunks.toString(); + } + + private String prepareTag(String tag) { + if (tag == null || "".equals(tag)) { + throw new EmitterException("tag must not be empty"); + } + if (tag.equals("!")) { + return tag; + } + String handle = null; + String suffix = tag; + for (String prefix : tagPrefixes.keySet()) { + if (tag.startsWith(prefix) && (prefix.equals("!") || prefix.length() < tag.length())) { + handle = tagPrefixes.get(prefix); + suffix = tag.substring(prefix.length()); + } + } + StringBuffer chunks = new StringBuffer(); + int start = 0; + int end = 0; + while (end < suffix.length()) { + end++; + } + if (start < end) { + chunks.append(suffix.substring(start, end)); + } + String suffixText = chunks.toString(); + if (handle != null) { + return handle + suffixText; + } else { + return "!<" + suffixText + ">"; + } + } + + private final static Pattern ANCHOR_FORMAT = Pattern.compile("^[-_\\w]*$"); + + static String prepareAnchor(String anchor) { + if (anchor == null || "".equals(anchor)) { + throw new EmitterException("anchor must not be empty"); + } + if (!ANCHOR_FORMAT.matcher(anchor).matches()) { + throw new EmitterException("invalid character in the anchor: " + anchor); + } + return anchor; + } + + private ScalarAnalysis analyzeScalar(String scalar) { + // Empty scalar is a special case. + if (scalar == null || "".equals(scalar)) { + return new ScalarAnalysis(scalar, true, false, false, true, true, true, false); + } + // Indicators and special characters. + boolean blockIndicators = false; + boolean flowIndicators = false; + boolean lineBreaks = false; + boolean specialCharacters = false; + + // Important whitespace combinations. + boolean leadingSpace = false; + boolean leadingBreak = false; + boolean trailingSpace = false; + boolean trailingBreak = false; + boolean breakSpace = false; + boolean spaceBreak = false; + + // Check document indicators. + if (scalar.startsWith("---") || scalar.startsWith("...")) { + blockIndicators = true; + flowIndicators = true; + } + // First character or preceded by a whitespace. + boolean preceededByWhitespace = true; + boolean followedByWhitespace = (scalar.length() == 1 || "\0 \t\r\n\u0085\u2029\u2029" + .indexOf(scalar.charAt(1)) != -1); + // The previous character is a space. + boolean previousSpace = false; + + // The previous character is a break. + boolean previousBreak = false; + + int index = 0; + + while (index < scalar.length()) { + char ch = scalar.charAt(index); + // Check for indicators. + if (index == 0) { + // Leading indicators are special characters. + if ("#,[]{}&*!|>\'\"%@`".indexOf(ch) != -1) { + flowIndicators = true; + blockIndicators = true; + } + if (ch == '?' || ch == ':') { + flowIndicators = true; + if (followedByWhitespace) { + blockIndicators = true; + } + } + if (ch == '-' && followedByWhitespace) { + flowIndicators = true; + blockIndicators = true; + } + } else { + // Some indicators cannot appear within a scalar as well. + if (",?[]{}".indexOf(ch) != -1) { + flowIndicators = true; + } + if (ch == ':') { + flowIndicators = true; + if (followedByWhitespace) { + blockIndicators = true; + } + } + if (ch == '#' && preceededByWhitespace) { + flowIndicators = true; + blockIndicators = true; + } + } + // Check for line breaks, special, and unicode characters. + if (ch == '\n' || ch == '\u0085' || ch == '\u2028' || ch == '\u2029') { + lineBreaks = true; + } + if (!(ch == '\n' || ('\u0020' <= ch && ch <= '\u007E'))) { + if ((ch == '\u0085' || ('\u00A0' <= ch && ch <= '\uD7FF') || ('\uE000' <= ch && ch <= '\uFFFD')) + && (ch != '\uFEFF')) { + // unicode is used + if (!this.allowUnicode) { + specialCharacters = true; + } + } else { + specialCharacters = true; + } + } + // Detect important whitespace combinations. + if (ch == ' ') { + if (index == 0) { + leadingSpace = true; + } + if (index == scalar.length() - 1) { + trailingSpace = true; + } + if (previousBreak) { + breakSpace = true; + } + previousSpace = true; + previousBreak = false; + } else if ("\n\u0085\u2028\u2029".indexOf(ch) != -1) { + if (index == 0) { + leadingBreak = true; + } + if (index == scalar.length() - 1) { + trailingBreak = true; + } + if (previousSpace) { + spaceBreak = true; + } + previousSpace = false; + previousBreak = true; + } else { + previousSpace = false; + previousBreak = false; + } + + // Prepare for the next character. + index++; + preceededByWhitespace = "\0 \t\r\n\u0085\u2028\u2029".indexOf(ch) != -1; + followedByWhitespace = (index + 1 >= scalar.length() || "\0 \t\r\n\u0085\u2028\u2029" + .indexOf(scalar.charAt(index + 1)) != -1); + } + // Let's decide what styles are allowed. + boolean allowFlowPlain = true; + boolean allowBlockPlain = true; + boolean allowSingleQuoted = true; + boolean allowDoubleQuoted = true; + boolean allowBlock = true; + // Leading and trailing whitespaces are bad for plain scalars. + if (leadingSpace || leadingBreak || trailingSpace || trailingBreak) { + allowFlowPlain = allowBlockPlain = false; + } + // We do not permit trailing spaces for block scalars. + if (trailingSpace) { + allowBlock = false; + } + // Spaces at the beginning of a new line are only acceptable for block + // scalars. + if (breakSpace) { + allowFlowPlain = allowBlockPlain = allowSingleQuoted = false; + } + // Spaces followed by breaks, as well as special character are only + // allowed for double quoted scalars. + if (spaceBreak || specialCharacters) { + allowFlowPlain = allowBlockPlain = allowSingleQuoted = allowBlock = false; + } + // Although the plain scalar writer supports breaks, we never emit + // multiline plain scalars. + if (lineBreaks) { + allowFlowPlain = allowBlockPlain = false; + } + // Flow indicators are forbidden for flow plain scalars. + if (flowIndicators) { + allowFlowPlain = false; + } + // Block indicators are forbidden for block plain scalars. + if (blockIndicators) { + allowBlockPlain = false; + } + + return new ScalarAnalysis(scalar, false, lineBreaks, allowFlowPlain, allowBlockPlain, + allowSingleQuoted, allowDoubleQuoted, allowBlock); + } + + // Writers. + + void flushStream() throws IOException { + stream.flush(); + } + + void writeStreamStart() { + // BOM is written by Writer. + } + + void writeStreamEnd() throws IOException { + flushStream(); + } + + void writeIndicator(String indicator, boolean needWhitespace, boolean whitespace, + boolean indentation) throws IOException { + String data = null; + if (this.whitespace || !needWhitespace) { + data = indicator; + } else { + data = " " + indicator; + } + this.whitespace = whitespace; + this.indention = this.indention && indentation; + this.column += data.length(); + openEnded = false; + stream.write(data); + } + + void writeIndent() throws IOException { + int indent; + if (this.indent != null) { + indent = this.indent; + } else { + indent = 0; + } + + if (!this.indention || this.column > indent || (this.column == indent && !this.whitespace)) { + writeLineBreak(null); + } + + if (this.column < indent) { + this.whitespace = true; + StringBuffer data = new StringBuffer(); + for (int i = 0; i < indent - this.column; i++) { + data.append(" "); + } + this.column = indent; + stream.write(data.toString()); + } + } + + private void writeLineBreak(String data) throws IOException { + if (data == null) { + data = this.bestLineBreak; + } + this.whitespace = true; + this.indention = true; + this.line++; + this.column = 0; + stream.write(data); + } + + void writeVersionDirective(String versionText) throws IOException { + stream.write("%YAML " + versionText); + writeLineBreak(null); + } + + void writeTagDirective(String handleText, String prefixText) throws IOException { + stream.write("%TAG " + handleText + " " + prefixText); + writeLineBreak(null); + } + + // Scalar streams. + private void writeSingleQuoted(String text, boolean split) throws IOException { + writeIndicator("'", true, false, false); + boolean spaces = false; + boolean breaks = false; + int start = 0, end = 0; + char ch; + while (end <= text.length()) { + ch = 0; + if (end < text.length()) { + ch = text.charAt(end); + } + if (spaces) { + if (ch == 0 || ch != ' ') { + if (start + 1 == end && this.column > this.bestWidth && split && start != 0 + && end != text.length()) { + writeIndent(); + } else { + String data = text.substring(start, end); + this.column += data.length(); + stream.write(data); + } + start = end; + } + } else if (breaks) { + if (ch == 0 || "\n\u0085\u2028\u2029".indexOf(ch) == -1) { + if (text.charAt(start) == '\n') { + writeLineBreak(null); + } + String data = text.substring(start, end); + for (char br : data.toCharArray()) { + if (br == '\n') { + writeLineBreak(null); + } else { + writeLineBreak(String.valueOf(br)); + } + } + writeIndent(); + start = end; + } + } else { + if (ch == 0 || " \n\u0085\u2028\u2029".indexOf(ch) != -1 || ch == '\'') { + if (start < end) { + String data = text.substring(start, end); + this.column += data.length(); + stream.write(data); + start = end; + } + } + } + if (ch == '\'') { + String data = "''"; + this.column += 2; + stream.write(data); + start = end + 1; + } + if (ch != 0) { + spaces = ch == ' '; + breaks = "\n\u0085\u2028\u2029".indexOf(ch) != -1; + } + end++; + } + writeIndicator("'", false, false, false); + } + + private void writeDoubleQuoted(String text, boolean split) throws IOException { + writeIndicator("\"", true, false, false); + int start = 0; + int end = 0; + while (end <= text.length()) { + Character ch = null; + if (end < text.length()) { + ch = text.charAt(end); + } + if (ch == null || "\"\\\u0085\u2028\u2029\uFEFF".indexOf(ch) != -1 + || !('\u0020' <= ch && ch <= '\u007E')) { + if (start < end) { + String data = text.substring(start, end); + this.column += data.length(); + stream.write(data); + start = end; + } + if (ch != null) { + String data; + if (ESCAPE_REPLACEMENTS.containsKey(new Character(ch))) { + data = "\\" + ESCAPE_REPLACEMENTS.get(new Character(ch)); + } else if (ch <= '\u00FF') { + String s = "0" + Integer.toString(ch, 16); + data = "\\x" + s.substring(s.length() - 2); + } else { + String s = "000" + Integer.toString(ch, 16); + data = "\\u" + s.substring(s.length() - 4); + } + this.column += data.length(); + stream.write(data); + start = end + 1; + } + } + if ((0 < end && end < (text.length() - 1)) && (ch == ' ' || start >= end) + && (this.column + (end - start)) > this.bestWidth && split) { + String data; + if (start >= end) { + data = "\\"; + } else { + data = text.substring(start, end) + "\\"; + } + if (start < end) { + start = end; + } + this.column += data.length(); + stream.write(data); + writeIndent(); + this.whitespace = false; + this.indention = false; + if (text.charAt(start) == ' ') { + data = "\\"; + this.column += data.length(); + stream.write(data); + } + } + end += 1; + } + writeIndicator("\"", false, false, false); + } + + private String determineBlockHints(String text) { + StringBuffer hints = new StringBuffer(); + if (text != null && text.length() > 0) { + if (" \n\u0085\u2028\u2029".indexOf(text.charAt(0)) != -1) { + hints.append(bestIndent); + } + char ch1 = text.charAt(text.length() - 1); + if ("\n\u0085\u2028\u2029".indexOf(ch1) == -1) { + hints.append("-"); + } else if (text.length() == 1 + || ("\n\u0085\u2028\u2029".indexOf(text.charAt(text.length() - 2)) != -1)) { + hints.append("+"); + } + } + return hints.toString(); + } + + void writeFolded(String text) throws IOException { + String hints = determineBlockHints(text); + writeIndicator(">" + hints, true, false, false); + if (hints.length() > 0 && (hints.charAt(hints.length() - 1) == '+')) { + openEnded = true; + } + writeLineBreak(null); + boolean leadingSpace = true; + boolean spaces = false; + boolean breaks = true; + int start = 0, end = 0; + while (end <= text.length()) { + char ch = 0; + if (end < text.length()) { + ch = text.charAt(end); + } + if (breaks) { + if (ch == 0 || ("\n\0085\u2028\u2029".indexOf(ch) == -1)) { + if (!leadingSpace && ch != 0 && ch != ' ' && text.charAt(start) == '\n') { + writeLineBreak(null); + } + leadingSpace = (ch == ' '); + String data = text.substring(start, end); + for (char br : data.toCharArray()) { + if (br == '\n') { + writeLineBreak(null); + } else { + writeLineBreak(String.valueOf(br)); + } + } + if (ch != 0) { + writeIndent(); + } + start = end; + } + } else if (spaces) { + if (ch != ' ') { + if (start + 1 == end && this.column > this.bestWidth) { + writeIndent(); + } else { + String data = text.substring(start, end); + this.column += data.length(); + stream.write(data); + } + start = end; + } + } else { + if (ch == 0 || " \n\0085\u2028\u2029".indexOf(ch) != -1) { + String data = text.substring(start, end); + stream.write(data); + if (ch == 0) { + writeLineBreak(null); + } + start = end; + } + } + if (ch != 0) { + breaks = ("\n\u0085\u2028\u2029".indexOf(ch) != -1); + spaces = (ch == ' '); + } + end++; + } + } + + void writeLiteral(String text) throws IOException { + String hints = determineBlockHints(text); + writeIndicator("|" + hints, true, false, false); + if (hints.length() > 0 && (hints.charAt(hints.length() - 1)) == '+') { + openEnded = true; + } + writeLineBreak(null); + boolean breaks = true; + int start = 0, end = 0; + while (end <= text.length()) { + char ch = 0; + if (end < text.length()) { + ch = text.charAt(end); + } + if (breaks) { + if (ch == 0 || "\n\u0085\u2028\u2029".indexOf(ch) == -1) { + String data = text.substring(start, end); + for (char br : data.toCharArray()) { + if (br == '\n') { + writeLineBreak(null); + } else { + writeLineBreak(String.valueOf(br)); + } + } + if (ch != 0) { + writeIndent(); + } + start = end; + } + } else { + if (ch == 0 || "\n\u0085\u2028\u2029".indexOf(ch) != -1) { + String data = text.substring(start, end); + stream.write(data); + if (ch == 0) { + writeLineBreak(null); + } + start = end; + } + } + if (ch != 0) { + breaks = ("\n\u0085\u2028\u2029".indexOf(ch) != -1); + } + end++; + } + } + + void writePlain(String text, boolean split) throws IOException { + if (rootContext) { + openEnded = true; + } + if (text == null || "".equals(text)) { + return; + } + if (!this.whitespace) { + String data = " "; + this.column += data.length(); + stream.write(data); + } + this.whitespace = false; + this.indention = false; + boolean spaces = false; + boolean breaks = false; + int start = 0, end = 0; + while (end <= text.length()) { + char ch = 0; + if (end < text.length()) { + ch = text.charAt(end); + } + if (spaces) { + if (ch != ' ') { + if (start + 1 == end && this.column > this.bestWidth && split) { + writeIndent(); + this.whitespace = false; + this.indention = false; + } else { + String data = text.substring(start, end); + this.column += data.length(); + stream.write(data); + } + start = end; + } + } else if (breaks) { + if ("\n\u0085\u2028\u2029".indexOf(ch) == -1) { + if (text.charAt(start) == '\n') { + writeLineBreak(null); + } + String data = text.substring(start, end); + for (char br : data.toCharArray()) { + if (br == '\n') { + writeLineBreak(null); + } else { + writeLineBreak(String.valueOf(br)); + } + } + writeIndent(); + this.whitespace = false; + this.indention = false; + start = end; + } + } else { + if (ch == 0 || "\n\u0085\u2028\u2029".indexOf(ch) != -1) { + String data = text.substring(start, end); + this.column += data.length(); + stream.write(data); + start = end; + } + } + if (ch != 0) { + spaces = (ch == ' '); + breaks = ("\n\u0085\u2028\u2029".indexOf(ch) != -1); + } + end++; + } + } +} diff --git a/src/main/java/org/yaml/snakeyaml/emitter/EmitterException.java b/src/main/java/org/yaml/snakeyaml/emitter/EmitterException.java new file mode 100644 index 00000000..b63e0c4e --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/emitter/EmitterException.java @@ -0,0 +1,17 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.emitter; + +import org.yaml.snakeyaml.error.YAMLException; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public class EmitterException extends YAMLException { + private static final long serialVersionUID = -8280070025452995908L; + + public EmitterException(String msg) { + super(msg); + } +} diff --git a/src/main/java/org/yaml/snakeyaml/emitter/EmitterState.java b/src/main/java/org/yaml/snakeyaml/emitter/EmitterState.java new file mode 100755 index 00000000..e7667fb5 --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/emitter/EmitterState.java @@ -0,0 +1,15 @@ +/**
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.emitter;
+
+import java.io.IOException;
+
+/**
+ * Python's methods are first class object. Java needs a class.
+ *
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+interface EmitterState {
+ void expect() throws IOException;
+}
\ No newline at end of file diff --git a/src/main/java/org/yaml/snakeyaml/emitter/ScalarAnalysis.java b/src/main/java/org/yaml/snakeyaml/emitter/ScalarAnalysis.java new file mode 100644 index 00000000..61ea599b --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/emitter/ScalarAnalysis.java @@ -0,0 +1,31 @@ +/**
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.emitter;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+final class ScalarAnalysis {
+ public String scalar;
+ public boolean empty;
+ public boolean multiline;
+ public boolean allowFlowPlain;
+ public boolean allowBlockPlain;
+ public boolean allowSingleQuoted;
+ public boolean allowDoubleQuoted;
+ public boolean allowBlock;
+
+ public ScalarAnalysis(String scalar, boolean empty, boolean multiline, boolean allowFlowPlain,
+ boolean allowBlockPlain, boolean allowSingleQuoted, boolean allowDoubleQuoted,
+ boolean allowBlock) {
+ this.scalar = scalar;
+ this.empty = empty;
+ this.multiline = multiline;
+ this.allowFlowPlain = allowFlowPlain;
+ this.allowBlockPlain = allowBlockPlain;
+ this.allowSingleQuoted = allowSingleQuoted;
+ this.allowDoubleQuoted = allowDoubleQuoted;
+ this.allowBlock = allowBlock;
+ }
+}
\ No newline at end of file diff --git a/src/main/java/org/yaml/snakeyaml/error/Mark.java b/src/main/java/org/yaml/snakeyaml/error/Mark.java new file mode 100644 index 00000000..d8341f7a --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/error/Mark.java @@ -0,0 +1,107 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.error;
+
+import org.yaml.snakeyaml.scanner.ScannerImpl;
+
+/**
+ * It's just a record and its only use is producing nice error messages. Parser
+ * does not use it for any other purposes.
+ *
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public final class Mark {
+ private String name;
+ private int line;
+ private int column;
+ private String buffer;
+ private int pointer;
+
+ public Mark(String name, int index, int line, int column, String buffer, int pointer) {
+ super();
+ this.name = name;
+ this.line = line;
+ this.column = column;
+ this.buffer = buffer;
+ this.pointer = pointer;
+ }
+
+ private boolean isLineBreak(char ch) {
+ return ScannerImpl.NULL_OR_LINEBR.indexOf(ch) != -1;
+ }
+
+ public String get_snippet(int indent, int max_length) {
+ if (buffer == null) {
+ return null;
+ }
+ float half = max_length / 2 - 1;
+ int start = pointer;
+ String head = "";
+ while ((start > 0) && (!isLineBreak(buffer.charAt(start - 1)))) {
+ start -= 1;
+ if (pointer - start > half) {
+ head = " ... ";
+ start += 5;
+ break;
+ }
+ }
+ String tail = "";
+ int end = pointer;
+ while ((end < buffer.length()) && (!isLineBreak(buffer.charAt(end)))) {
+ end += 1;
+ if (end - pointer > half) {
+ tail = " ... ";
+ end -= 5;
+ break;
+ }
+ }
+ String snippet = buffer.substring(start, end);
+ StringBuffer result = new StringBuffer();
+ for (int i = 0; i < indent; i++) {
+ result.append(" ");
+ }
+ result.append(head);
+ result.append(snippet);
+ result.append(tail);
+ result.append("\n");
+ for (int i = 0; i < indent + pointer - start + head.length(); i++) {
+ result.append(" ");
+ }
+ result.append("^");
+ return result.toString();
+ }
+
+ public String get_snippet() {
+ return get_snippet(4, 75);
+ }
+
+ @Override
+ public String toString() {
+ String snippet = get_snippet();
+ StringBuffer where = new StringBuffer(" in \"");
+ where.append(name);
+ where.append("\", line ");
+ where.append(line);
+ where.append(", column ");
+ where.append(column);
+ if (snippet != null) {
+ where.append(":\n");
+ where.append(snippet);
+ }
+ return where.toString();
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public int getLine() {
+ return line;
+ }
+
+ public int getColumn() {
+ return column;
+ }
+
+}
diff --git a/src/main/java/org/yaml/snakeyaml/error/MarkedYAMLException.java b/src/main/java/org/yaml/snakeyaml/error/MarkedYAMLException.java new file mode 100644 index 00000000..aff6dcc5 --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/error/MarkedYAMLException.java @@ -0,0 +1,61 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.error;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public class MarkedYAMLException extends YAMLException {
+
+ private static final long serialVersionUID = -9119388488683035101L;
+ private String context;
+ private Mark contextMark;
+ private String problem;
+ private Mark problemMark;
+ private String note;
+
+ protected MarkedYAMLException(String context, Mark contextMark, String problem,
+ Mark problemMark, String note) {
+ super(context + "; " + problem);
+ this.context = context;
+ this.contextMark = contextMark;
+ this.problem = problem;
+ this.problemMark = problemMark;
+ this.note = note;
+ }
+
+ protected MarkedYAMLException(String context, Mark contextMark, String problem, Mark problemMark) {
+ this(context, contextMark, problem, problemMark, null);
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer lines = new StringBuffer();
+ if (context != null) {
+ lines.append(context);
+ lines.append("\n");
+ }
+ if (contextMark != null
+ && (problem == null || problemMark == null
+ || (contextMark.getName() != problemMark.getName())
+ || (contextMark.getLine() != problemMark.getLine()) || (contextMark
+ .getColumn() != problemMark.getColumn()))) {
+ lines.append(contextMark.toString());
+ lines.append("\n");
+ }
+ if (problem != null) {
+ lines.append(problem);
+ lines.append("\n");
+ }
+ if (problemMark != null) {
+ lines.append(problemMark.toString());
+ lines.append("\n");
+ }
+ if (note != null) {
+ lines.append(note);
+ lines.append("\n");
+ }
+ return lines.toString();
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/error/YAMLException.java b/src/main/java/org/yaml/snakeyaml/error/YAMLException.java new file mode 100644 index 00000000..4a90a987 --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/error/YAMLException.java @@ -0,0 +1,19 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.error; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public class YAMLException extends RuntimeException { + private static final long serialVersionUID = -4738336175050337570L; + + public YAMLException(String message) { + super(message); + } + + public YAMLException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/org/yaml/snakeyaml/events/AliasEvent.java b/src/main/java/org/yaml/snakeyaml/events/AliasEvent.java new file mode 100644 index 00000000..431580cb --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/events/AliasEvent.java @@ -0,0 +1,15 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.events; + +import org.yaml.snakeyaml.error.Mark; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public final class AliasEvent extends NodeEvent { + public AliasEvent(String anchor, Mark startMark, Mark endMark) { + super(anchor, startMark, endMark); + } +} diff --git a/src/main/java/org/yaml/snakeyaml/events/CollectionEndEvent.java b/src/main/java/org/yaml/snakeyaml/events/CollectionEndEvent.java new file mode 100644 index 00000000..283db3b6 --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/events/CollectionEndEvent.java @@ -0,0 +1,16 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.events; + +import org.yaml.snakeyaml.error.Mark; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public abstract class CollectionEndEvent extends Event { + + public CollectionEndEvent(Mark startMark, Mark endMark) { + super(startMark, endMark); + } +} diff --git a/src/main/java/org/yaml/snakeyaml/events/CollectionStartEvent.java b/src/main/java/org/yaml/snakeyaml/events/CollectionStartEvent.java new file mode 100644 index 00000000..19d5dc47 --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/events/CollectionStartEvent.java @@ -0,0 +1,40 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.events; + +import org.yaml.snakeyaml.error.Mark; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public abstract class CollectionStartEvent extends NodeEvent { + private final String tag; + private final boolean implicit; + private final Boolean flowStyle; + + public CollectionStartEvent(String anchor, String tag, boolean implicit, Mark startMark, + Mark endMark, Boolean flowStyle) { + super(anchor, startMark, endMark); + this.tag = tag; + this.implicit = implicit; + this.flowStyle = flowStyle; + } + + public String getTag() { + return this.tag; + } + + public boolean getImplicit() { + return this.implicit; + } + + public Boolean getFlowStyle() { + return this.flowStyle; + } + + @Override + protected String getArguments() { + return super.getArguments() + ", tag=" + tag + ", implicit=" + implicit; + } +} diff --git a/src/main/java/org/yaml/snakeyaml/events/DocumentEndEvent.java b/src/main/java/org/yaml/snakeyaml/events/DocumentEndEvent.java new file mode 100644 index 00000000..fff13b97 --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/events/DocumentEndEvent.java @@ -0,0 +1,22 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.events; + +import org.yaml.snakeyaml.error.Mark; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public final class DocumentEndEvent extends Event { + private final boolean explicit; + + public DocumentEndEvent(Mark startMark, Mark endMark, boolean explicit) { + super(startMark, endMark); + this.explicit = explicit; + } + + public boolean getExplicit() { + return explicit; + } +} diff --git a/src/main/java/org/yaml/snakeyaml/events/DocumentStartEvent.java b/src/main/java/org/yaml/snakeyaml/events/DocumentStartEvent.java new file mode 100644 index 00000000..051661f4 --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/events/DocumentStartEvent.java @@ -0,0 +1,37 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.events; + +import java.util.Map; + +import org.yaml.snakeyaml.error.Mark; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public final class DocumentStartEvent extends Event { + private final boolean explicit; + private final Integer[] version; + private final Map<String, String> tags; + + public DocumentStartEvent(Mark startMark, Mark endMark, boolean explicit, Integer[] version, + Map<String, String> tags) { + super(startMark, endMark); + this.explicit = explicit; + this.version = version; + this.tags = tags; + } + + public boolean getExplicit() { + return explicit; + } + + public Integer[] getVersion() { + return version; + } + + public Map<String, String> getTags() { + return tags; + } +} diff --git a/src/main/java/org/yaml/snakeyaml/events/Event.java b/src/main/java/org/yaml/snakeyaml/events/Event.java new file mode 100644 index 00000000..858793bd --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/events/Event.java @@ -0,0 +1,51 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.events; + +import org.yaml.snakeyaml.error.Mark; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public abstract class Event { + private final Mark startMark; + private final Mark endMark; + + public Event(Mark startMark, Mark endMark) { + this.startMark = startMark; + this.endMark = endMark; + } + + public String toString() { + return "<" + this.getClass().getName() + "(" + getArguments() + ")>"; + } + + public Mark getStartMark() { + return startMark; + } + + public Mark getEndMark() { + return endMark; + } + + /** + * @see __repr__ for Event in PyYAML + */ + protected String getArguments() { + return ""; + } + + /* + * for tests only + */ + @Override + public boolean equals(Object obj) { + if (obj instanceof Event) { + return toString().equals(obj.toString()); + } else { + return false; + } + } + +} diff --git a/src/main/java/org/yaml/snakeyaml/events/MappingEndEvent.java b/src/main/java/org/yaml/snakeyaml/events/MappingEndEvent.java new file mode 100644 index 00000000..f90bba36 --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/events/MappingEndEvent.java @@ -0,0 +1,16 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.events; + +import org.yaml.snakeyaml.error.Mark; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public final class MappingEndEvent extends CollectionEndEvent { + + public MappingEndEvent(Mark startMark, Mark endMark) { + super(startMark, endMark); + } +} diff --git a/src/main/java/org/yaml/snakeyaml/events/MappingStartEvent.java b/src/main/java/org/yaml/snakeyaml/events/MappingStartEvent.java new file mode 100644 index 00000000..97cb7aaf --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/events/MappingStartEvent.java @@ -0,0 +1,16 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.events; + +import org.yaml.snakeyaml.error.Mark; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public final class MappingStartEvent extends CollectionStartEvent { + public MappingStartEvent(String anchor, String tag, boolean implicit, Mark startMark, + Mark endMark, Boolean flowStyle) { + super(anchor, tag, implicit, startMark, endMark, flowStyle); + } +} diff --git a/src/main/java/org/yaml/snakeyaml/events/NodeEvent.java b/src/main/java/org/yaml/snakeyaml/events/NodeEvent.java new file mode 100644 index 00000000..5c31d958 --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/events/NodeEvent.java @@ -0,0 +1,28 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.events; + +import org.yaml.snakeyaml.error.Mark; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public abstract class NodeEvent extends Event { + + private final String anchor; + + public NodeEvent(String anchor, Mark startMark, Mark endMark) { + super(startMark, endMark); + this.anchor = anchor; + } + + public String getAnchor() { + return this.anchor; + } + + @Override + protected String getArguments() { + return "anchor=" + anchor; + } +} diff --git a/src/main/java/org/yaml/snakeyaml/events/ScalarEvent.java b/src/main/java/org/yaml/snakeyaml/events/ScalarEvent.java new file mode 100644 index 00000000..b76d9b7f --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/events/ScalarEvent.java @@ -0,0 +1,48 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.events; + +import org.yaml.snakeyaml.error.Mark; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public final class ScalarEvent extends NodeEvent { + private final String tag; + private final Character style; + private final String value; + private final boolean[] implicit; + + public ScalarEvent(String anchor, String tag, boolean[] implicit, String value, Mark startMark, + Mark endMark, Character style) { + super(anchor, startMark, endMark); + this.tag = tag; + this.implicit = implicit; + this.value = value; + this.style = style; + } + + public String getTag() { + return this.tag; + } + + public Character getStyle() { + return this.style; + } + + public String getValue() { + return this.value; + } + + public boolean[] getImplicit() { + return this.implicit; + } + + @Override + protected String getArguments() { + return super.getArguments() + ", tag=" + tag + ", implicit=[" + implicit[0] + ", " + + implicit[1] + "], value=" + value; + } + +} diff --git a/src/main/java/org/yaml/snakeyaml/events/SequenceEndEvent.java b/src/main/java/org/yaml/snakeyaml/events/SequenceEndEvent.java new file mode 100644 index 00000000..e98552d9 --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/events/SequenceEndEvent.java @@ -0,0 +1,16 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.events; + +import org.yaml.snakeyaml.error.Mark; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public final class SequenceEndEvent extends CollectionEndEvent { + + public SequenceEndEvent(Mark startMark, Mark endMark) { + super(startMark, endMark); + } +} diff --git a/src/main/java/org/yaml/snakeyaml/events/SequenceStartEvent.java b/src/main/java/org/yaml/snakeyaml/events/SequenceStartEvent.java new file mode 100644 index 00000000..769d6137 --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/events/SequenceStartEvent.java @@ -0,0 +1,16 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.events; + +import org.yaml.snakeyaml.error.Mark; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public final class SequenceStartEvent extends CollectionStartEvent { + public SequenceStartEvent(String anchor, String tag, boolean implicit, Mark startMark, + Mark endMark, Boolean flowStyle) { + super(anchor, tag, implicit, startMark, endMark, flowStyle); + } +} diff --git a/src/main/java/org/yaml/snakeyaml/events/StreamEndEvent.java b/src/main/java/org/yaml/snakeyaml/events/StreamEndEvent.java new file mode 100644 index 00000000..861a6129 --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/events/StreamEndEvent.java @@ -0,0 +1,15 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.events; + +import org.yaml.snakeyaml.error.Mark; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public final class StreamEndEvent extends Event { + public StreamEndEvent(Mark startMark, Mark endMark) { + super(startMark, endMark); + } +} diff --git a/src/main/java/org/yaml/snakeyaml/events/StreamStartEvent.java b/src/main/java/org/yaml/snakeyaml/events/StreamStartEvent.java new file mode 100644 index 00000000..3a7ee20c --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/events/StreamStartEvent.java @@ -0,0 +1,16 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.events; + +import org.yaml.snakeyaml.error.Mark; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public final class StreamStartEvent extends Event { + + public StreamStartEvent(Mark startMark, Mark endMark) { + super(startMark, endMark); + } +} diff --git a/src/main/java/org/yaml/snakeyaml/introspector/FieldProperty.java b/src/main/java/org/yaml/snakeyaml/introspector/FieldProperty.java new file mode 100644 index 00000000..6faa0955 --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/introspector/FieldProperty.java @@ -0,0 +1,32 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.introspector; + +import java.lang.reflect.Field; + +import org.yaml.snakeyaml.error.YAMLException; + +public class FieldProperty extends Property { + private final Field field; + + public FieldProperty(Field field) { + super(field.getName(), field.getType()); + this.field = field; + } + + @Override + public void set(Object object, Object value) throws Exception { + field.set(object, value); + } + + @Override + public Object get(Object object) { + try { + return field.get(object); + } catch (Exception e) { + throw new YAMLException("Unable to access field " + field.getName() + " on object " + + object + " : " + e); + } + } +}
\ No newline at end of file diff --git a/src/main/java/org/yaml/snakeyaml/introspector/MethodProperty.java b/src/main/java/org/yaml/snakeyaml/introspector/MethodProperty.java new file mode 100644 index 00000000..5a4c3922 --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/introspector/MethodProperty.java @@ -0,0 +1,32 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.introspector; + +import java.beans.PropertyDescriptor; + +import org.yaml.snakeyaml.error.YAMLException; + +public class MethodProperty extends Property { + private final PropertyDescriptor property; + + public MethodProperty(PropertyDescriptor property) { + super(property.getName(), property.getPropertyType()); + this.property = property; + } + + @Override + public void set(Object object, Object value) throws Exception { + property.getWriteMethod().invoke(object, value); + } + + @Override + public Object get(Object object) { + try { + return property.getReadMethod().invoke(object); + } catch (Exception e) { + throw new YAMLException("Unable to find getter for property " + property.getName() + + " on object " + object + ":" + e); + } + } +}
\ No newline at end of file diff --git a/src/main/java/org/yaml/snakeyaml/introspector/Property.java b/src/main/java/org/yaml/snakeyaml/introspector/Property.java new file mode 100644 index 00000000..c815b0a0 --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/introspector/Property.java @@ -0,0 +1,35 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.introspector;
+
+public abstract class Property implements Comparable<Property> {
+ private final String name;
+ private final Class<? extends Object> type;
+
+ public Property(String name, Class<? extends Object> type) {
+ this.name = name;
+ this.type = type;
+ }
+
+ public Class<? extends Object> getType() {
+ return type;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String toString() {
+ return getName() + " of " + getType();
+ }
+
+ public int compareTo(Property o) {
+ return name.compareTo(o.name);
+ }
+
+ abstract public void set(Object object, Object value) throws Exception;
+
+ abstract public Object get(Object object);
+}
\ No newline at end of file diff --git a/src/main/java/org/yaml/snakeyaml/nodes/CollectionNode.java b/src/main/java/org/yaml/snakeyaml/nodes/CollectionNode.java new file mode 100644 index 00000000..b414b10d --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/nodes/CollectionNode.java @@ -0,0 +1,30 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.nodes; + +import org.yaml.snakeyaml.error.Mark; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public abstract class CollectionNode extends Node { + private Boolean flowStyle; + + public CollectionNode(String tag, Object value, Mark startMark, Mark endMark, Boolean flowStyle) { + super(tag, value, startMark, endMark); + this.flowStyle = flowStyle; + } + + public Boolean getFlowStyle() { + return flowStyle; + } + + public void setFlowStyle(Boolean flowStyle) { + this.flowStyle = flowStyle; + } + + public void setEndMark(Mark endMark) { + this.endMark = endMark; + } +} diff --git a/src/main/java/org/yaml/snakeyaml/nodes/MappingNode.java b/src/main/java/org/yaml/snakeyaml/nodes/MappingNode.java new file mode 100644 index 00000000..b3e233cd --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/nodes/MappingNode.java @@ -0,0 +1,71 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.nodes; + +import java.util.List; + +import org.yaml.snakeyaml.error.Mark; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public class MappingNode extends CollectionNode { + private Class<? extends Object> keyType; + private Class<? extends Object> valueType; + + public MappingNode(String tag, List<Node[]> value, Mark startMark, Mark endMark, + Boolean flowStyle) { + super(tag, value, startMark, endMark, flowStyle); + keyType = Object.class; + valueType = Object.class; + } + + public MappingNode(String tag, List<Node[]> value, Boolean flowStyle) { + super(tag, value, null, null, flowStyle); + } + + @Override + public NodeId getNodeId() { + return NodeId.mapping; + } + + @SuppressWarnings("unchecked") + @Override + public List<Node[]> getValue() { + List<Node[]> mapping = (List<Node[]>) super.getValue(); + for (Node[] nodes : mapping) { + nodes[0].setType(keyType); + nodes[1].setType(valueType); + } + return mapping; + } + + public void setValue(List<Node[]> merge) { + value = merge; + } + + public void setKeyType(Class<? extends Object> keyType) { + this.keyType = keyType; + } + + public void setValueType(Class<? extends Object> valueType) { + this.valueType = valueType; + } + + @Override + public String toString() { + String values; + StringBuffer buf = new StringBuffer(); + for (Node[] node : getValue()) { + buf.append("{ key="); + buf.append(node[0]); + buf.append("; value="); + // to avoid overflow in case of recursive structures + buf.append(System.identityHashCode(node[1])); + buf.append(" }"); + } + values = buf.toString(); + return "<" + this.getClass().getName() + " (tag=" + getTag() + ", values=" + values + ")>"; + } +} diff --git a/src/main/java/org/yaml/snakeyaml/nodes/Node.java b/src/main/java/org/yaml/snakeyaml/nodes/Node.java new file mode 100644 index 00000000..69cbbf3a --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/nodes/Node.java @@ -0,0 +1,76 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.nodes; + +import org.yaml.snakeyaml.error.Mark; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public abstract class Node { + private String tag; + protected Object value; + private Mark startMark; + protected Mark endMark; + private Class<? extends Object> type; + + public Node(String tag, Object value, Mark startMark, Mark endMark) { + setTag(tag); + if (value == null) { + throw new NullPointerException("value in a Node is required."); + } + this.value = value; + this.startMark = startMark; + this.endMark = endMark; + this.type = Object.class; + } + + public String getTag() { + return this.tag; + } + + public Object getValue() { + return this.value; + } + + public String toString() { + return "<" + this.getClass().getName() + " (tag=" + getTag() + ", value=" + getValue() + + ")>"; + } + + /** + * For error reporting. + * + * @see class variable 'id' in PyYAML + * @return scalar, sequence, mapping + */ + public abstract NodeId getNodeId(); + + public Mark getStartMark() { + return startMark; + } + + public void setTag(String tag) { + if (tag == null) { + throw new NullPointerException("tag in a Node is required."); + } + this.tag = tag; + } + + /* + * It is not allowed to overwrite this method. Two Nodes are never equal. + */ + @Override + public final boolean equals(Object obj) { + return super.equals(obj); + } + + public Class<? extends Object> getType() { + return type; + } + + public void setType(Class<? extends Object> type) { + this.type = type; + } +} diff --git a/src/main/java/org/yaml/snakeyaml/nodes/NodeId.java b/src/main/java/org/yaml/snakeyaml/nodes/NodeId.java new file mode 100644 index 00000000..956114c1 --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/nodes/NodeId.java @@ -0,0 +1,8 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.nodes;
+
+public enum NodeId {
+ scalar, sequence, mapping;
+}
diff --git a/src/main/java/org/yaml/snakeyaml/nodes/ScalarNode.java b/src/main/java/org/yaml/snakeyaml/nodes/ScalarNode.java new file mode 100644 index 00000000..b7bb544e --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/nodes/ScalarNode.java @@ -0,0 +1,27 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.nodes; + +import org.yaml.snakeyaml.error.Mark; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public class ScalarNode extends Node { + private Character style; + + public ScalarNode(String tag, String value, Mark startMark, Mark endMark, Character style) { + super(tag, value, startMark, endMark); + this.style = style; + } + + public Character getStyle() { + return style; + } + + @Override + public NodeId getNodeId() { + return NodeId.scalar; + } +} diff --git a/src/main/java/org/yaml/snakeyaml/nodes/SequenceNode.java b/src/main/java/org/yaml/snakeyaml/nodes/SequenceNode.java new file mode 100644 index 00000000..48914174 --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/nodes/SequenceNode.java @@ -0,0 +1,43 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.nodes; + +import java.util.List; + +import org.yaml.snakeyaml.error.Mark; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public class SequenceNode extends CollectionNode { + private Class<? extends Object> listType; + + public SequenceNode(String tag, List<Node> value, Mark startMark, Mark endMark, + Boolean flowStyle) { + super(tag, value, startMark, endMark, flowStyle); + listType = Object.class; + } + + public SequenceNode(String tag, List<Node> value, Boolean flowStyle) { + this(tag, value, null, null, flowStyle); + } + + @Override + public NodeId getNodeId() { + return NodeId.sequence; + } + + @SuppressWarnings("unchecked") + public List<Node> getValue() { + List<Node> value = (List<Node>) super.getValue(); + for (Node node : value) { + node.setType(listType); + } + return value; + } + + public void setListType(Class<? extends Object> listType) { + this.listType = listType; + } +} diff --git a/src/main/java/org/yaml/snakeyaml/parser/Parser.java b/src/main/java/org/yaml/snakeyaml/parser/Parser.java new file mode 100644 index 00000000..6564de0b --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/parser/Parser.java @@ -0,0 +1,22 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.parser; + +import java.util.List; + +import org.yaml.snakeyaml.events.Event; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public interface Parser { + public boolean checkEvent(List<Class<? extends Event>> choices); + + public boolean checkEvent(Class<? extends Event> choice); + + public Event peekEvent(); + + public Event getEvent(); + +} diff --git a/src/main/java/org/yaml/snakeyaml/parser/ParserException.java b/src/main/java/org/yaml/snakeyaml/parser/ParserException.java new file mode 100644 index 00000000..9a866b67 --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/parser/ParserException.java @@ -0,0 +1,18 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.parser; + +import org.yaml.snakeyaml.error.Mark; +import org.yaml.snakeyaml.error.MarkedYAMLException; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public class ParserException extends MarkedYAMLException { + private static final long serialVersionUID = -2349253802798398038L; + + public ParserException(String context, Mark contextMark, String problem, Mark problemMark) { + super(context, contextMark, problem, problemMark, null); + } +} diff --git a/src/main/java/org/yaml/snakeyaml/parser/ParserImpl.java b/src/main/java/org/yaml/snakeyaml/parser/ParserImpl.java new file mode 100644 index 00000000..865a1d03 --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/parser/ParserImpl.java @@ -0,0 +1,855 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.parser; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.yaml.snakeyaml.error.Mark; +import org.yaml.snakeyaml.error.YAMLException; +import org.yaml.snakeyaml.events.AliasEvent; +import org.yaml.snakeyaml.events.DocumentEndEvent; +import org.yaml.snakeyaml.events.DocumentStartEvent; +import org.yaml.snakeyaml.events.Event; +import org.yaml.snakeyaml.events.MappingEndEvent; +import org.yaml.snakeyaml.events.MappingStartEvent; +import org.yaml.snakeyaml.events.ScalarEvent; +import org.yaml.snakeyaml.events.SequenceEndEvent; +import org.yaml.snakeyaml.events.SequenceStartEvent; +import org.yaml.snakeyaml.events.StreamEndEvent; +import org.yaml.snakeyaml.events.StreamStartEvent; +import org.yaml.snakeyaml.scanner.Scanner; +import org.yaml.snakeyaml.scanner.ScannerImpl; +import org.yaml.snakeyaml.tokens.AliasToken; +import org.yaml.snakeyaml.tokens.AnchorToken; +import org.yaml.snakeyaml.tokens.BlockEndToken; +import org.yaml.snakeyaml.tokens.BlockEntryToken; +import org.yaml.snakeyaml.tokens.BlockMappingStartToken; +import org.yaml.snakeyaml.tokens.BlockSequenceStartToken; +import org.yaml.snakeyaml.tokens.DirectiveToken; +import org.yaml.snakeyaml.tokens.DocumentEndToken; +import org.yaml.snakeyaml.tokens.DocumentStartToken; +import org.yaml.snakeyaml.tokens.FlowEntryToken; +import org.yaml.snakeyaml.tokens.FlowMappingEndToken; +import org.yaml.snakeyaml.tokens.FlowMappingStartToken; +import org.yaml.snakeyaml.tokens.FlowSequenceEndToken; +import org.yaml.snakeyaml.tokens.FlowSequenceStartToken; +import org.yaml.snakeyaml.tokens.KeyToken; +import org.yaml.snakeyaml.tokens.ScalarToken; +import org.yaml.snakeyaml.tokens.StreamEndToken; +import org.yaml.snakeyaml.tokens.StreamStartToken; +import org.yaml.snakeyaml.tokens.TagToken; +import org.yaml.snakeyaml.tokens.Token; +import org.yaml.snakeyaml.tokens.ValueToken; + +/** + * <pre> + * # The following YAML grammar is LL(1) and is parsed by a recursive descent + * parser. + * stream ::= STREAM-START implicit_document? explicit_document* STREAM-END + * implicit_document ::= block_node DOCUMENT-END* + * explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* + * block_node_or_indentless_sequence ::= + * ALIAS + * | properties (block_content | indentless_block_sequence)? + * | block_content + * | indentless_block_sequence + * block_node ::= ALIAS + * | properties block_content? + * | block_content + * flow_node ::= ALIAS + * | properties flow_content? + * | flow_content + * properties ::= TAG ANCHOR? | ANCHOR TAG? + * block_content ::= block_collection | flow_collection | SCALAR + * flow_content ::= flow_collection | SCALAR + * block_collection ::= block_sequence | block_mapping + * flow_collection ::= flow_sequence | flow_mapping + * block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END + * indentless_sequence ::= (BLOCK-ENTRY block_node?)+ + * block_mapping ::= BLOCK-MAPPING_START + * ((KEY block_node_or_indentless_sequence?)? + * (VALUE block_node_or_indentless_sequence?)?)* + * BLOCK-END + * flow_sequence ::= FLOW-SEQUENCE-START + * (flow_sequence_entry FLOW-ENTRY)* + * flow_sequence_entry? + * FLOW-SEQUENCE-END + * flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? + * flow_mapping ::= FLOW-MAPPING-START + * (flow_mapping_entry FLOW-ENTRY)* + * flow_mapping_entry? + * FLOW-MAPPING-END + * flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? + * FIRST sets: + * stream: { STREAM-START } + * explicit_document: { DIRECTIVE DOCUMENT-START } + * implicit_document: FIRST(block_node) + * block_node: { ALIAS TAG ANCHOR SCALAR BLOCK-SEQUENCE-START BLOCK-MAPPING-START FLOW-SEQUENCE-START FLOW-MAPPING-START } + * flow_node: { ALIAS ANCHOR TAG SCALAR FLOW-SEQUENCE-START FLOW-MAPPING-START } + * block_content: { BLOCK-SEQUENCE-START BLOCK-MAPPING-START FLOW-SEQUENCE-START FLOW-MAPPING-START SCALAR } + * flow_content: { FLOW-SEQUENCE-START FLOW-MAPPING-START SCALAR } + * block_collection: { BLOCK-SEQUENCE-START BLOCK-MAPPING-START } + * flow_collection: { FLOW-SEQUENCE-START FLOW-MAPPING-START } + * block_sequence: { BLOCK-SEQUENCE-START } + * block_mapping: { BLOCK-MAPPING-START } + * block_node_or_indentless_sequence: { ALIAS ANCHOR TAG SCALAR BLOCK-SEQUENCE-START BLOCK-MAPPING-START FLOW-SEQUENCE-START FLOW-MAPPING-START BLOCK-ENTRY } + * indentless_sequence: { ENTRY } + * flow_collection: { FLOW-SEQUENCE-START FLOW-MAPPING-START } + * flow_sequence: { FLOW-SEQUENCE-START } + * flow_mapping: { FLOW-MAPPING-START } + * flow_sequence_entry: { ALIAS ANCHOR TAG SCALAR FLOW-SEQUENCE-START FLOW-MAPPING-START KEY } + * flow_mapping_entry: { ALIAS ANCHOR TAG SCALAR FLOW-SEQUENCE-START FLOW-MAPPING-START KEY } + * </pre> + * + * Since writing a recursive-descendant parser is a straightforward task, we do + * not give many comments here. + * + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public final class ParserImpl implements Parser { + private static final Map<String, String> DEFAULT_TAGS = new HashMap<String, String>(); + static { + DEFAULT_TAGS.put("!", "!"); + DEFAULT_TAGS.put("!!", "tag:yaml.org,2002:"); + } + + private final Scanner scanner; + private Event currentEvent; + private List<Integer> yamlVersion; + private Map<String, String> tagHandles; + private final LinkedList<Production> states; + private final LinkedList<Mark> marks; + private Production state; + + public ParserImpl(org.yaml.snakeyaml.reader.Reader reader) { + this.scanner = new ScannerImpl(reader); + currentEvent = null; + yamlVersion = null; + tagHandles = new HashMap<String, String>(); + states = new LinkedList<Production>(); + marks = new LinkedList<Mark>(); + state = new ParseStreamStart(); + } + + /** + * Check the type of the next event. + */ + public boolean checkEvent(List<Class<? extends Event>> choices) { + peekEvent(); + if (currentEvent != null) { + if (choices.size() == 0) { + return true; + } + for (Class<? extends Event> class1 : choices) { + if (class1.isInstance(currentEvent)) { + return true; + } + } + } + return false; + } + + /** + * Check the type of the next event. + */ + public boolean checkEvent(Class<? extends Event> cls) { + List<Class<? extends Event>> list = new ArrayList<Class<? extends Event>>(1); + list.add(cls); + return checkEvent(list); + } + + /* + * Get the next event. + */ + public Event peekEvent() { + if (currentEvent == null) { + if (state != null) { + currentEvent = state.produce(); + } + } + return currentEvent; + } + + /* + * Get the next event and proceed further. + */ + public Event getEvent() { + peekEvent(); + Event value = currentEvent; + currentEvent = null; + return value; + } + + /** + * <pre> + * stream ::= STREAM-START implicit_document? explicit_document* STREAM-END + * implicit_document ::= block_node DOCUMENT-END* + * explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* + * </pre> + */ + private class ParseStreamStart implements Production { + public Event produce() { + // Parse the stream start. + StreamStartToken token = (StreamStartToken) scanner.getToken(); + Event event = new StreamStartEvent(token.getStartMark(), token.getEndMark()); + // Prepare the next state. + state = new ParseImplicitDocumentStart(); + return event; + } + } + + private class ParseImplicitDocumentStart implements Production { + public Event produce() { + // Parse an implicit document. + List<Class<? extends Token>> choices = new ArrayList<Class<? extends Token>>(); + choices.add(DirectiveToken.class); + choices.add(DocumentStartToken.class); + choices.add(StreamEndToken.class); + if (!scanner.checkToken(choices)) { + tagHandles = DEFAULT_TAGS; + Token token = scanner.peekToken(); + Mark startMark = token.getStartMark(); + Mark endMark = startMark; + Event event = new DocumentStartEvent(startMark, endMark, false, null, null); + // Prepare the next state. + states.add(new ParseDocumentEnd()); + state = new ParseBlockNode(); + return event; + } else { + Production p = new ParseDocumentStart(); + return p.produce(); + } + } + } + + private class ParseDocumentStart implements Production { + @SuppressWarnings("unchecked") + public Event produce() { + // Parse any extra document end indicators. + while (scanner.checkToken(DocumentEndToken.class)) { + scanner.getToken(); + } + // Parse an explicit document. + Event event; + if (!scanner.checkToken(StreamEndToken.class)) { + Token token = scanner.peekToken(); + Mark startMark = token.getStartMark(); + List<Object> version_tags = processDirectives(); + List<Object> version = (List<Object>) version_tags.get(0); + Map<String, String> tags = (Map<String, String>) version_tags.get(1); + if (!scanner.checkToken(DocumentStartToken.class)) { + throw new ParserException(null, null, "expected '<document start>', but found " + + scanner.peekToken().getTokenId(), scanner.peekToken().getStartMark()); + } + token = scanner.getToken(); + Mark endMark = token.getEndMark(); + Integer[] versionInteger; + if (version != null) { + versionInteger = new Integer[2]; + versionInteger = version.toArray(versionInteger); + } else { + versionInteger = null; + } + event = new DocumentStartEvent(startMark, endMark, true, versionInteger, tags); + states.add(new ParseDocumentEnd()); + state = new ParseDocumentContent(); + } else { + // Parse the end of the stream. + StreamEndToken token = (StreamEndToken) scanner.getToken(); + event = new StreamEndEvent(token.getStartMark(), token.getEndMark()); + if (!states.isEmpty()) { + throw new YAMLException("Unexpected end of stream. States left: " + states); + } + if (!marks.isEmpty()) { + throw new YAMLException("Unexpected end of stream. Marks left: " + marks); + } + state = null; + } + return event; + } + } + + private class ParseDocumentEnd implements Production { + public Event produce() { + // Parse the document end. + Token token = scanner.peekToken(); + Mark startMark = token.getStartMark(); + Mark endMark = startMark; + boolean explicit = false; + if (scanner.checkToken(DocumentEndToken.class)) { + token = scanner.getToken(); + endMark = token.getEndMark(); + explicit = true; + } + Event event = new DocumentEndEvent(startMark, endMark, explicit); + // Prepare the next state. + state = new ParseDocumentStart(); + return event; + } + } + + private class ParseDocumentContent implements Production { + public Event produce() { + List<Class<? extends Token>> choices = new ArrayList<Class<? extends Token>>(); + choices.add(DirectiveToken.class); + choices.add(DocumentStartToken.class); + choices.add(DocumentEndToken.class); + choices.add(StreamEndToken.class); + Event event; + if (scanner.checkToken(choices)) { + event = processEmptyScalar(scanner.peekToken().getStartMark()); + state = states.removeLast(); + return event; + } else { + Production p = new ParseBlockNode(); + return p.produce(); + } + } + } + + @SuppressWarnings("unchecked") + private List<Object> processDirectives() { + yamlVersion = null; + tagHandles = new HashMap<String, String>(); + while (scanner.checkToken(DirectiveToken.class)) { + DirectiveToken token = (DirectiveToken) scanner.getToken(); + if (token.getName().equals("YAML")) { + if (yamlVersion != null) { + throw new ParserException(null, null, "found duplicate YAML directive", token + .getStartMark()); + } + List<Integer> value = (List<Integer>) token.getValue(); + Integer major = value.get(0); + if (major != 1) { + throw new ParserException(null, null, + "found incompatible YAML document (version 1.* is required)", token + .getStartMark()); + } + yamlVersion = (List<Integer>) token.getValue(); + } else if (token.getName().equals("TAG")) { + List<String> value = (List<String>) token.getValue(); + String handle = value.get(0); + String prefix = value.get(1); + if (tagHandles.containsKey(handle)) { + throw new ParserException(null, null, "duplicate tag handle " + handle, token + .getStartMark()); + } + tagHandles.put(handle, prefix); + } + } + List<Object> value = new ArrayList<Object>(2); + value.add(yamlVersion); + if (!tagHandles.isEmpty()) { + value.add(new HashMap<String, String>(tagHandles)); + } else { + value.add(new HashMap<String, String>()); + } + for (String key : DEFAULT_TAGS.keySet()) { + if (!tagHandles.containsKey(key)) { + tagHandles.put(key, DEFAULT_TAGS.get(key)); + } + } + return value; + } + + /** + * <pre> + * block_node_or_indentless_sequence ::= ALIAS + * | properties (block_content | indentless_block_sequence)? + * | block_content + * | indentless_block_sequence + * block_node ::= ALIAS + * | properties block_content? + * | block_content + * flow_node ::= ALIAS + * | properties flow_content? + * | flow_content + * properties ::= TAG ANCHOR? | ANCHOR TAG? + * block_content ::= block_collection | flow_collection | SCALAR + * flow_content ::= flow_collection | SCALAR + * block_collection ::= block_sequence | block_mapping + * flow_collection ::= flow_sequence | flow_mapping + * </pre> + */ + + private class ParseBlockNode implements Production { + public Event produce() { + return parseNode(true, false); + } + } + + private Event parseFlowNode() { + return parseNode(false, false); + } + + private Event parseBlockNodeOrIndentlessSequence() { + return parseNode(true, true); + } + + private Event parseNode(boolean block, boolean indentlessSequence) { + Event event; + Mark startMark = null; + Mark endMark = null; + Mark tagMark = null; + if (scanner.checkToken(AliasToken.class)) { + AliasToken token = (AliasToken) scanner.getToken(); + event = new AliasEvent(token.getValue(), token.getStartMark(), token.getEndMark()); + state = states.removeLast(); + } else { + String anchor = null; + String[] tagTokenTag = null; + if (scanner.checkToken(AnchorToken.class)) { + AnchorToken token = (AnchorToken) scanner.getToken(); + startMark = token.getStartMark(); + endMark = token.getEndMark(); + anchor = token.getValue(); + if (scanner.checkToken(TagToken.class)) { + TagToken tagToken = (TagToken) scanner.getToken(); + tagMark = tagToken.getStartMark(); + endMark = tagToken.getEndMark(); + tagTokenTag = tagToken.getValue(); + } + } else if (scanner.checkToken(TagToken.class)) { + TagToken tagToken = (TagToken) scanner.getToken(); + startMark = tagToken.getStartMark(); + tagMark = startMark; + endMark = tagToken.getEndMark(); + tagTokenTag = tagToken.getValue(); + if (scanner.checkToken(AnchorToken.class)) { + AnchorToken token = (AnchorToken) scanner.getToken(); + endMark = token.getEndMark(); + anchor = token.getValue(); + } + } + String tag = null; + if (tagTokenTag != null) { + String handle = tagTokenTag[0]; + String suffix = tagTokenTag[1]; + if (handle != null) { + if (!tagHandles.containsKey(handle)) { + throw new ParserException("while parsing a node", startMark, + "found undefined tag handle " + handle, tagMark); + } + tag = tagHandles.get(handle) + suffix; + } else { + tag = suffix; + } + } + if (startMark == null) { + startMark = scanner.peekToken().getStartMark(); + endMark = startMark; + } + event = null; + boolean implicit = (tag == null || tag.equals("!")); + if (indentlessSequence && scanner.checkToken(BlockEntryToken.class)) { + endMark = scanner.peekToken().getEndMark(); + event = new SequenceStartEvent(anchor, tag, implicit, startMark, endMark, + Boolean.FALSE); + state = new ParseIndentlessSequenceEntry(); + } else { + if (scanner.checkToken(ScalarToken.class)) { + ScalarToken token = (ScalarToken) scanner.getToken(); + endMark = token.getEndMark(); + boolean[] implicitValues = new boolean[2]; + if ((token.getPlain() && tag == null) || "!".equals(tag)) { + implicitValues[0] = true; + implicitValues[1] = false; + } else if (tag == null) { + implicitValues[0] = false; + implicitValues[1] = true; + } else { + implicitValues[0] = false; + implicitValues[1] = false; + } + event = new ScalarEvent(anchor, tag, implicitValues, token.getValue(), + startMark, endMark, token.getStyle()); + state = states.removeLast(); + } else if (scanner.checkToken(FlowSequenceStartToken.class)) { + endMark = scanner.peekToken().getEndMark(); + event = new SequenceStartEvent(anchor, tag, implicit, startMark, endMark, + Boolean.TRUE); + state = new ParseFlowSequenceFirstEntry(); + } else if (scanner.checkToken(FlowMappingStartToken.class)) { + endMark = scanner.peekToken().getEndMark(); + event = new MappingStartEvent(anchor, tag, implicit, startMark, endMark, + Boolean.TRUE); + state = new ParseFlowMappingFirstKey(); + } else if (block && scanner.checkToken(BlockSequenceStartToken.class)) { + endMark = scanner.peekToken().getStartMark(); + event = new SequenceStartEvent(anchor, tag, implicit, startMark, endMark, + Boolean.FALSE); + state = new ParseBlockSequenceFirstEntry(); + } else if (block && scanner.checkToken(BlockMappingStartToken.class)) { + endMark = scanner.peekToken().getStartMark(); + event = new MappingStartEvent(anchor, tag, implicit, startMark, endMark, + Boolean.FALSE); + state = new ParseBlockMappingFirstKey(); + } else if (anchor != null || tag != null) { + // Empty scalars are allowed even if a tag or an anchor is + // specified. + boolean[] implicitValues = new boolean[2]; + implicitValues[0] = implicit; + implicitValues[1] = false; + event = new ScalarEvent(anchor, tag, implicitValues, "", startMark, endMark, + (char) 0); + state = states.removeLast(); + } else { + String node; + if (block) { + node = "block"; + } else { + node = "flow"; + } + Token token = scanner.peekToken(); + throw new ParserException("while parsing a " + node + " node", startMark, + "expected the node content, but found " + token.getTokenId(), token + .getStartMark()); + } + } + } + return event; + } + + // block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* + // BLOCK-END + + private class ParseBlockSequenceFirstEntry implements Production { + public Event produce() { + Token token = scanner.getToken(); + marks.add(token.getStartMark()); + return new ParseBlockSequenceEntry().produce(); + } + } + + private class ParseBlockSequenceEntry implements Production { + public Event produce() { + if (scanner.checkToken(BlockEntryToken.class)) { + BlockEntryToken token = (BlockEntryToken) scanner.getToken(); + List<Class<? extends Token>> choices = new ArrayList<Class<? extends Token>>(); + choices.add(BlockEntryToken.class); + choices.add(BlockEndToken.class); + if (!scanner.checkToken(choices)) { + states.add(new ParseBlockSequenceEntry()); + return new ParseBlockNode().produce(); + } else { + state = new ParseBlockSequenceEntry(); + return processEmptyScalar(token.getEndMark()); + } + } + if (!scanner.checkToken(BlockEndToken.class)) { + Token token = scanner.peekToken(); + throw new ParserException("while parsing a block collection", marks.getLast(), + "expected <block end>, but found " + token.getTokenId(), token + .getStartMark()); + } + Token token = scanner.getToken(); + Event event = new SequenceEndEvent(token.getStartMark(), token.getEndMark()); + state = states.removeLast(); + marks.removeLast(); + return event; + } + } + + // indentless_sequence ::= (BLOCK-ENTRY block_node?)+ + + private class ParseIndentlessSequenceEntry implements Production { + public Event produce() { + if (scanner.checkToken(BlockEntryToken.class)) { + Token token = scanner.getToken(); + List<Class<? extends Token>> choices = new ArrayList<Class<? extends Token>>(); + choices.add(BlockEntryToken.class); + choices.add(KeyToken.class); + choices.add(ValueToken.class); + choices.add(BlockEndToken.class); + if (!scanner.checkToken(choices)) { + states.add(new ParseIndentlessSequenceEntry()); + return new ParseBlockNode().produce(); + } else { + state = new ParseIndentlessSequenceEntry(); + return processEmptyScalar(token.getEndMark()); + } + } + Token token = scanner.peekToken(); + Event event = new SequenceEndEvent(token.getStartMark(), token.getEndMark()); + state = states.removeLast(); + return event; + } + } + + private class ParseBlockMappingFirstKey implements Production { + public Event produce() { + Token token = scanner.getToken(); + marks.add(token.getStartMark()); + return new ParseBlockMappingKey().produce(); + } + } + + private class ParseBlockMappingKey implements Production { + public Event produce() { + if (scanner.checkToken(KeyToken.class)) { + Token token = scanner.getToken(); + List<Class<? extends Token>> choices = new ArrayList<Class<? extends Token>>(); + choices.add(KeyToken.class); + choices.add(ValueToken.class); + choices.add(BlockEndToken.class); + if (!scanner.checkToken(choices)) { + states.add(new ParseBlockMappingValue()); + return parseBlockNodeOrIndentlessSequence(); + } else { + state = new ParseBlockMappingValue(); + return processEmptyScalar(token.getEndMark()); + } + } + if (!scanner.checkToken(BlockEndToken.class)) { + Token token = scanner.peekToken(); + throw new ParserException("while parsing a block mapping", marks.getLast(), + "expected <block end>, but found " + token.getTokenId(), token + .getStartMark()); + } + Token token = scanner.getToken(); + Event event = new MappingEndEvent(token.getStartMark(), token.getEndMark()); + state = states.removeLast(); + marks.removeLast(); + return event; + } + } + + private class ParseBlockMappingValue implements Production { + public Event produce() { + if (scanner.checkToken(ValueToken.class)) { + Token token = scanner.getToken(); + List<Class<? extends Token>> choices = new ArrayList<Class<? extends Token>>(); + choices.add(KeyToken.class); + choices.add(ValueToken.class); + choices.add(BlockEndToken.class); + if (!scanner.checkToken(choices)) { + states.add(new ParseBlockMappingKey()); + return parseBlockNodeOrIndentlessSequence(); + } else { + state = new ParseBlockMappingKey(); + return processEmptyScalar(token.getEndMark()); + } + } + state = new ParseBlockMappingKey(); + Token token = scanner.peekToken(); + return processEmptyScalar(token.getStartMark()); + } + } + + /** + * <pre> + * flow_sequence ::= FLOW-SEQUENCE-START + * (flow_sequence_entry FLOW-ENTRY)* + * flow_sequence_entry? + * FLOW-SEQUENCE-END + * flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? + * Note that while production rules for both flow_sequence_entry and + * flow_mapping_entry are equal, their interpretations are different. + * For `flow_sequence_entry`, the part `KEY flow_node? (VALUE flow_node?)?` + * generate an inline mapping (set syntax). + * </pre> + */ + private class ParseFlowSequenceFirstEntry implements Production { + public Event produce() { + Token token = scanner.getToken(); + marks.add(token.getStartMark()); + return new ParseFlowSequenceEntry(true).produce(); + } + } + + private class ParseFlowSequenceEntry implements Production { + private boolean first = false; + + public ParseFlowSequenceEntry(boolean first) { + this.first = first; + } + + public Event produce() { + if (!scanner.checkToken(FlowSequenceEndToken.class)) { + if (!first) { + if (scanner.checkToken(FlowEntryToken.class)) { + scanner.getToken(); + } else { + Token token = scanner.peekToken(); + throw new ParserException("while parsing a flow sequence", marks.getLast(), + "expected ',' or ']', but got " + token.getTokenId(), token + .getStartMark()); + } + } + if (scanner.checkToken(KeyToken.class)) { + Token token = scanner.peekToken(); + Event event = new MappingStartEvent(null, null, true, token.getStartMark(), + token.getEndMark(), Boolean.TRUE); + state = new ParseFlowSequenceEntryMappingKey(); + return event; + } else if (!scanner.checkToken(FlowSequenceEndToken.class)) { + states.add(new ParseFlowSequenceEntry(false)); + return parseFlowNode(); + } + } + Token token = scanner.getToken(); + Event event = new SequenceEndEvent(token.getStartMark(), token.getEndMark()); + state = states.removeLast(); + marks.removeLast(); + return event; + } + } + + private class ParseFlowSequenceEntryMappingKey implements Production { + public Event produce() { + Token token = scanner.getToken(); + List<Class<? extends Token>> choices = new ArrayList<Class<? extends Token>>(); + choices.add(ValueToken.class); + choices.add(FlowEntryToken.class); + choices.add(FlowSequenceEndToken.class); + if (!scanner.checkToken(choices)) { + states.add(new ParseFlowSequenceEntryMappingValue()); + return parseFlowNode(); + } else { + state = new ParseFlowSequenceEntryMappingValue(); + return processEmptyScalar(token.getEndMark()); + } + } + } + + private class ParseFlowSequenceEntryMappingValue implements Production { + public Event produce() { + if (scanner.checkToken(ValueToken.class)) { + Token token = scanner.getToken(); + List<Class<? extends Token>> choices = new ArrayList<Class<? extends Token>>(); + choices.add(FlowEntryToken.class); + choices.add(FlowSequenceEndToken.class); + if (!scanner.checkToken(choices)) { + states.add(new ParseFlowSequenceEntryMappingEnd()); + return parseFlowNode(); + } else { + state = new ParseFlowSequenceEntryMappingEnd(); + return processEmptyScalar(token.getEndMark()); + } + } else { + state = new ParseFlowSequenceEntryMappingEnd(); + Token token = scanner.peekToken(); + return processEmptyScalar(token.getStartMark()); + } + } + } + + private class ParseFlowSequenceEntryMappingEnd implements Production { + public Event produce() { + state = new ParseFlowSequenceEntry(false); + Token token = scanner.peekToken(); + return new MappingEndEvent(token.getStartMark(), token.getEndMark()); + } + } + + /** + * <pre> + * flow_mapping ::= FLOW-MAPPING-START + * (flow_mapping_entry FLOW-ENTRY)* + * flow_mapping_entry? + * FLOW-MAPPING-END + * flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? + * </pre> + */ + private class ParseFlowMappingFirstKey implements Production { + public Event produce() { + Token token = scanner.getToken(); + marks.add(token.getStartMark()); + return new ParseFlowMappingKey(true).produce(); + } + } + + private class ParseFlowMappingKey implements Production { + private boolean first = false; + + public ParseFlowMappingKey(boolean first) { + this.first = first; + } + + public Event produce() { + if (!scanner.checkToken(FlowMappingEndToken.class)) { + if (!first) { + if (scanner.checkToken(FlowEntryToken.class)) { + scanner.getToken(); + } else { + Token token = scanner.peekToken(); + throw new ParserException("while parsing a flow mapping", marks.getLast(), + "expected ',' or '}', but got " + token.getTokenId(), token + .getStartMark()); + } + } + if (scanner.checkToken(KeyToken.class)) { + Token token = scanner.getToken(); + List<Class<? extends Token>> choices = new ArrayList<Class<? extends Token>>(); + choices.add(ValueToken.class); + choices.add(FlowEntryToken.class); + choices.add(FlowMappingEndToken.class); + if (!scanner.checkToken(choices)) { + states.add(new ParseFlowMappingValue()); + return parseFlowNode(); + } else { + state = new ParseFlowMappingValue(); + return processEmptyScalar(token.getEndMark()); + } + } else if (!scanner.checkToken(FlowMappingEndToken.class)) { + states.add(new ParseFlowMappingEmptyValue()); + return parseFlowNode(); + } + } + Token token = scanner.getToken(); + Event event = new MappingEndEvent(token.getStartMark(), token.getEndMark()); + state = states.removeLast(); + marks.removeLast(); + return event; + } + } + + private class ParseFlowMappingValue implements Production { + public Event produce() { + if (scanner.checkToken(ValueToken.class)) { + Token token = scanner.getToken(); + List<Class<? extends Token>> choices = new ArrayList<Class<? extends Token>>(); + choices.add(FlowEntryToken.class); + choices.add(FlowMappingEndToken.class); + if (!scanner.checkToken(choices)) { + states.add(new ParseFlowMappingKey(false)); + return parseFlowNode(); + } else { + state = new ParseFlowMappingKey(false); + return processEmptyScalar(token.getEndMark()); + } + } else { + state = new ParseFlowMappingKey(false); + Token token = scanner.peekToken(); + return processEmptyScalar(token.getStartMark()); + } + } + } + + private class ParseFlowMappingEmptyValue implements Production { + public Event produce() { + state = new ParseFlowMappingKey(false); + return processEmptyScalar(scanner.peekToken().getStartMark()); + } + } + + /** + * <pre> + * block_mapping ::= BLOCK-MAPPING_START + * ((KEY block_node_or_indentless_sequence?)? + * (VALUE block_node_or_indentless_sequence?)?)* + * BLOCK-END + * </pre> + */ + private Event processEmptyScalar(Mark mark) { + boolean[] value = new boolean[2]; + value[0] = true; + value[1] = false; + return new ScalarEvent(null, null, value, "", mark, mark, (char) 0); + } +} diff --git a/src/main/java/org/yaml/snakeyaml/parser/Production.java b/src/main/java/org/yaml/snakeyaml/parser/Production.java new file mode 100644 index 00000000..92e6bc4a --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/parser/Production.java @@ -0,0 +1,10 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.parser;
+
+import org.yaml.snakeyaml.events.Event;
+
+interface Production {
+ public Event produce();
+}
diff --git a/src/main/java/org/yaml/snakeyaml/reader/Reader.java b/src/main/java/org/yaml/snakeyaml/reader/Reader.java new file mode 100644 index 00000000..885bb74a --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/reader/Reader.java @@ -0,0 +1,175 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.reader;
+
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.yaml.snakeyaml.error.Mark;
+import org.yaml.snakeyaml.error.YAMLException;
+
+/**
+ * Reader: determines the data encoding and converts it to unicode, checks if
+ * characters are in allowed range, adds '\0' to the end.
+ *
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public class Reader {
+ // NON_PRINTABLE changed from PyYAML: \uFFFD excluded because Java returns
+ // it in case of data corruption
+ final static Pattern NON_PRINTABLE = Pattern
+ .compile("[^\t\n\r\u0020-\u007E\u0085\u00A0-\uD7FF\uE000-\uFFFC]");
+ private final static String LINEBR = "\n\u0085\u2028\u2029";
+
+ private String name;
+ private final java.io.Reader stream;
+ private int pointer = 0;
+ private boolean eof = true;
+ private final StringBuffer buffer;
+ private int index = 0;
+ private int line = 0;
+ private int column = 0;
+
+ public Reader(String stream) {
+ this.name = "<string>";
+ this.buffer = new StringBuffer();
+ checkPrintable(stream);
+ this.buffer.append(stream);
+ this.stream = null;
+ this.eof = true;
+ }
+
+ public Reader(java.io.Reader reader) {
+ this.name = "<reader>";
+ this.buffer = new StringBuffer();
+ this.stream = reader;
+ this.eof = false;
+ }
+
+ void checkPrintable(CharSequence data) {
+ Matcher em = NON_PRINTABLE.matcher(data);
+ if (em.find()) {
+ int position = this.index + this.buffer.length() - this.pointer + em.start();
+ throw new ReaderException(name, position, em.group().charAt(0),
+ " special characters are not allowed");
+ }
+ }
+
+ public Mark getMark() {
+ if (this.stream == null) {
+ return new Mark(name, this.index, this.line, this.column, this.buffer.toString(),
+ this.pointer);
+ } else {
+ return new Mark(name, this.index, this.line, this.column, null, 0);
+ }
+ }
+
+ public void forward() {
+ forward(1);
+ }
+
+ /**
+ * read the next length characters and move the pointer.
+ *
+ * @param length
+ */
+ public void forward(int length) {
+ if (this.pointer + length + 1 >= this.buffer.length()) {
+ update(length + 1);
+ }
+ char ch = 0;
+ for (int i = 0; i < length; i++) {
+ ch = this.buffer.charAt(this.pointer);
+ this.pointer++;
+ this.index++;
+ if (LINEBR.indexOf(ch) != -1
+ || (ch == '\r' && this.buffer.charAt(this.pointer) != '\n')) {
+ this.line++;
+ this.column = 0;
+ } else if (ch != '\uFEFF') {
+ this.column++;
+ }
+ }
+ }
+
+ public char peek() {
+ return peek(0);
+ }
+
+ /**
+ * Peek the next index-th character
+ *
+ * @param index
+ * @return
+ */
+ public char peek(int index) {
+ if (this.pointer + index + 1 > this.buffer.length()) {
+ update(index + 1);
+ }
+ return this.buffer.charAt(this.pointer + index);
+ }
+
+ /**
+ * peek the next length characters
+ *
+ * @param length
+ * @return
+ */
+ public String prefix(int length) {
+ if (this.pointer + length >= this.buffer.length()) {
+ update(length);
+ }
+ if (this.pointer + length > this.buffer.length()) {
+ return this.buffer.substring(this.pointer, this.buffer.length());
+ } else {
+ return this.buffer.substring(this.pointer, this.pointer + length);
+ }
+ }
+
+ private void update(int length) {
+ this.buffer.delete(0, this.pointer);
+ this.pointer = 0;
+ while (this.buffer.length() < length) {
+ String rawData = "";
+ if (!this.eof) {
+ char[] data = new char[1024];
+ int converted = -2;
+ try {
+ converted = this.stream.read(data);
+ } catch (IOException ioe) {
+ throw new YAMLException(ioe);
+ }
+ if (converted == -1) {
+ this.eof = true;
+ } else {
+ rawData = new String(data, 0, converted);
+ }
+ }
+ checkPrintable(rawData);
+ this.buffer.append(rawData);
+ if (this.eof) {
+ this.buffer.append('\0');
+ break;
+ }
+ }
+ }
+
+ public int getColumn() {
+ return column;
+ }
+
+ public Charset getEncoding() {
+ return Charset.forName(((UnicodeReader) this.stream).getEncoding());
+ }
+
+ public int getIndex() {
+ return index;
+ }
+
+ public int getLine() {
+ return line;
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/reader/ReaderException.java b/src/main/java/org/yaml/snakeyaml/reader/ReaderException.java new file mode 100644 index 00000000..7239f3f5 --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/reader/ReaderException.java @@ -0,0 +1,26 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.reader;
+
+import org.yaml.snakeyaml.error.YAMLException;
+
+public class ReaderException extends YAMLException {
+ private static final long serialVersionUID = 8710781187529689083L;
+ private String name;
+ private char character;
+ private int position;
+
+ public ReaderException(String name, int position, char character, String message) {
+ super(message);
+ this.name = name;
+ this.character = character;
+ this.position = position;
+ }
+
+ @Override
+ public String toString() {
+ return "unacceptable character #" + Integer.toHexString((int) character).toUpperCase()
+ + " " + getMessage() + "\nin \"" + name + "\", position " + position;
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/reader/UnicodeReader.java b/src/main/java/org/yaml/snakeyaml/reader/UnicodeReader.java new file mode 100644 index 00000000..07081393 --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/reader/UnicodeReader.java @@ -0,0 +1,105 @@ +package org.yaml.snakeyaml.reader; + +/** + version: 1.1 / 2007-01-25 + - changed BOM recognition ordering (longer boms first) + + Original pseudocode : Thomas Weidenfeller + Implementation tweaked: Aki Nieminen + Implementation changed: Andrey Somov + * UTF-32 removed because it is not supported by YAML + * no default encoding + + http://www.unicode.org/unicode/faq/utf_bom.html + BOMs: + 00 00 FE FF = UTF-32, big-endian + FF FE 00 00 = UTF-32, little-endian + EF BB BF = UTF-8, + FE FF = UTF-16, big-endian + FF FE = UTF-16, little-endian + + Win2k Notepad: + Unicode format = UTF-16LE + ***/ + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.PushbackInputStream; + +/** + * Generic unicode textreader, which will use BOM mark to identify the encoding + * to be used. If BOM is not found then use a given default or system encoding. + */ +public class UnicodeReader extends java.io.Reader { + PushbackInputStream internalIn; + InputStreamReader internalIn2 = null; + + private static final int BOM_SIZE = 3; + + /** + * + * @param in + * InputStream to be read + * @param defaultEnc + * default encoding if stream does not have BOM marker. Give NULL + * to use system-level default. + */ + public UnicodeReader(InputStream in) { + internalIn = new PushbackInputStream(in, BOM_SIZE); + } + + /** + * Get stream encoding or NULL if stream is uninitialized. Call init() or + * read() method to initialize it. + */ + public String getEncoding() { + return internalIn2.getEncoding(); + } + + /** + * Read-ahead four bytes and check for BOM marks. Extra bytes are unread + * back to the stream, only BOM bytes are skipped. + */ + protected void init() throws IOException { + if (internalIn2 != null) + return; + + String encoding; + byte bom[] = new byte[BOM_SIZE]; + int n, unread; + n = internalIn.read(bom, 0, bom.length); + + if ((bom[0] == (byte) 0xEF) && (bom[1] == (byte) 0xBB) && (bom[2] == (byte) 0xBF)) { + encoding = "UTF-8"; + unread = n - 3; + } else if ((bom[0] == (byte) 0xFE) && (bom[1] == (byte) 0xFF)) { + encoding = "UTF-16BE"; + unread = n - 2; + } else if ((bom[0] == (byte) 0xFF) && (bom[1] == (byte) 0xFE)) { + encoding = "UTF-16LE"; + unread = n - 2; + } else { + // Unicode BOM mark not found, unread all bytes + encoding = "UTF-8"; + unread = n; + } + + if (unread > 0) + internalIn.unread(bom, (n - unread), unread); + + // Use given encoding + internalIn2 = new InputStreamReader(internalIn, encoding); + } + + public void close() throws IOException { + init(); + internalIn2.close(); + } + + public int read(char[] cbuf, int off, int len) throws IOException { + init(); + return internalIn2.read(cbuf, off, len); + } + +}
\ No newline at end of file diff --git a/src/main/java/org/yaml/snakeyaml/representer/BaseRepresenter.java b/src/main/java/org/yaml/snakeyaml/representer/BaseRepresenter.java new file mode 100644 index 00000000..b1c94292 --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/representer/BaseRepresenter.java @@ -0,0 +1,161 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.representer;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.yaml.snakeyaml.error.YAMLException;
+import org.yaml.snakeyaml.nodes.MappingNode;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.ScalarNode;
+import org.yaml.snakeyaml.nodes.SequenceNode;
+import org.yaml.snakeyaml.serializer.Serializer;
+
+public abstract class BaseRepresenter {
+ @SuppressWarnings("unchecked")
+ protected final Map<Class, Represent> representers = new HashMap<Class, Represent>();
+ /**
+ * in Java 'null' is not a type. So we have to keep the null representer
+ * separately otherwise it will coincide with the default representer which
+ * is stored with the key null.
+ */
+ protected Represent nullRepresenter;
+ @SuppressWarnings("unchecked")
+ protected final Map<Class, Represent> multiRepresenters = new HashMap<Class, Represent>();
+ private Character defaultStyle;
+ protected Boolean defaultFlowStyle;
+ protected final Map<Integer, Node> representedObjects = new HashMap<Integer, Node>();
+ private final Set<Object> objectKeeper = new HashSet<Object>();
+ protected Integer aliasKey;// internal memory address
+ protected String rootTag = null;
+
+ public BaseRepresenter(Character default_style, Boolean default_flow_style) {
+ this.defaultStyle = default_style;
+ this.defaultFlowStyle = default_flow_style;
+ }
+
+ public void represent(Serializer serializer, Object data) throws IOException {
+ Node node = representData(data);
+ serializer.serialize(node);
+ representedObjects.clear();
+ objectKeeper.clear();
+ }
+
+ @SuppressWarnings("unchecked")
+ protected Node representData(Object data) {
+ aliasKey = System.identityHashCode(data);// take memory address
+ if (!ignoreAliases(data)) {
+ // check for identity
+ if (representedObjects.containsKey(aliasKey)) {
+ Node node = representedObjects.get(aliasKey);
+ return node;
+ }
+ }
+ // check for null first
+ if (data == null) {
+ Node node = nullRepresenter.representData(data);
+ return node;
+ }
+ // check the same class
+ Node node;
+ Class clazz = data.getClass();
+ if (representers.containsKey(clazz)) {
+ Represent representer = representers.get(clazz);
+ node = representer.representData(data);
+ } else {
+ // check the parents
+ for (Class repr : multiRepresenters.keySet()) {
+ if (repr.isInstance(data)) {
+ Represent representer = multiRepresenters.get(repr);
+ node = representer.representData(data);
+ return node;
+ }
+ }
+ // check array of primitives
+ if (clazz.isArray()) {
+ throw new YAMLException("Arrays of primitives are not fully supported.");
+ }
+ // check defaults
+ if (multiRepresenters.containsKey(null)) {
+ Represent representer = multiRepresenters.get(null);
+ node = representer.representData(data);
+ } else {
+ Represent representer = representers.get(null);
+ node = representer.representData(data);
+ }
+ }
+ return node;
+ }
+
+ protected Node representScalar(String tag, String value, Character style) {
+ if (style == null) {
+ style = this.defaultStyle;
+ }
+ Node node = new ScalarNode(tag, value, null, null, style);
+ representedObjects.put(aliasKey, node);
+ return node;
+ }
+
+ protected Node representScalar(String tag, String value) {
+ return representScalar(tag, value, null);
+ }
+
+ protected Node representSequence(String tag, List<? extends Object> sequence, Boolean flowStyle) {
+ List<Node> value = new LinkedList<Node>();
+ SequenceNode node = new SequenceNode(tag, value, flowStyle);
+ representedObjects.put(aliasKey, node);
+ boolean bestStyle = true;
+ for (Object item : sequence) {
+ Node nodeItem = representData(item);
+ if (!((nodeItem instanceof ScalarNode && ((ScalarNode) nodeItem).getStyle() == null))) {
+ bestStyle = false;
+ }
+ value.add(nodeItem);
+ }
+ if (flowStyle == null) {
+ if (defaultFlowStyle != null) {
+ node.setFlowStyle(defaultFlowStyle);
+ } else {
+ node.setFlowStyle(bestStyle);
+ }
+ }
+ return node;
+ }
+
+ protected Node representMapping(String tag, Map<? extends Object, Object> mapping,
+ Boolean flowStyle) {
+ List<Node[]> value = new LinkedList<Node[]>();
+ MappingNode node = new MappingNode(tag, value, flowStyle);
+ representedObjects.put(aliasKey, node);
+ boolean bestStyle = true;
+ for (Object itemKey : mapping.keySet()) {
+ Object itemValue = mapping.get(itemKey);
+ Node nodeKey = representData(itemKey);
+ Node nodeValue = representData(itemValue);
+ if (!((nodeKey instanceof ScalarNode && ((ScalarNode) nodeKey).getStyle() == null))) {
+ bestStyle = false;
+ }
+ if (!((nodeValue instanceof ScalarNode && ((ScalarNode) nodeValue).getStyle() == null))) {
+ bestStyle = false;
+ }
+ value.add(new Node[] { nodeKey, nodeValue });
+ }
+ if (flowStyle == null) {
+ if (defaultFlowStyle != null) {
+ node.setFlowStyle(defaultFlowStyle);
+ } else {
+ node.setFlowStyle(bestStyle);
+ }
+ }
+ return node;
+ }
+
+ protected abstract boolean ignoreAliases(Object data);
+}
diff --git a/src/main/java/org/yaml/snakeyaml/representer/Represent.java b/src/main/java/org/yaml/snakeyaml/representer/Represent.java new file mode 100644 index 00000000..e51e7bea --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/representer/Represent.java @@ -0,0 +1,10 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.representer; + +import org.yaml.snakeyaml.nodes.Node; + +public interface Represent { + public Node representData(Object data); +} diff --git a/src/main/java/org/yaml/snakeyaml/representer/Representer.java b/src/main/java/org/yaml/snakeyaml/representer/Representer.java new file mode 100644 index 00000000..baa4e3e5 --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/representer/Representer.java @@ -0,0 +1,143 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.representer; + +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; + +import org.yaml.snakeyaml.TypeDescription; +import org.yaml.snakeyaml.error.YAMLException; +import org.yaml.snakeyaml.introspector.FieldProperty; +import org.yaml.snakeyaml.introspector.MethodProperty; +import org.yaml.snakeyaml.introspector.Property; +import org.yaml.snakeyaml.nodes.MappingNode; +import org.yaml.snakeyaml.nodes.Node; +import org.yaml.snakeyaml.nodes.ScalarNode; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public class Representer extends SafeRepresenter { + private Map<Class<? extends Object>, String> classTags; + private Map<Class<? extends Object>, TypeDescription> classDefinitions; + + public Representer(Character default_style, Boolean default_flow_style) { + super(default_style, default_flow_style); + classTags = new HashMap<Class<? extends Object>, String>(); + classDefinitions = new HashMap<Class<? extends Object>, TypeDescription>(); + this.representers.put(null, new RepresentJavaBean()); + } + + public Representer() { + this(null, null); + } + + /** + * Make YAML aware how to represent a custom Class. If there is no root + * Class assigned in constructor then the 'root' property of this definition + * is respected. + * + * @param definition + * to be added to the Constructor + * @return the previous value associated with <tt>definition</tt>, or + * <tt>null</tt> if there was no mapping for <tt>definition</tt>. + */ + public TypeDescription addTypeDescription(TypeDescription definition) { + if (definition == null) { + throw new NullPointerException("ClassDescription is required."); + } + String tag = definition.getTag(); + classTags.put(definition.getType(), tag); + return classDefinitions.put(definition.getType(), definition); + } + + private class RepresentJavaBean implements Represent { + public Node representData(Object data) { + Set<Property> properties; + try { + properties = getProperties(data.getClass()); + } catch (IntrospectionException e) { + throw new YAMLException(e); + } + Node node = representMapping(properties, data); + return node; + } + } + + private Node representMapping(Set<Property> properties, Object javaBean) { + List<Node[]> value = new LinkedList<Node[]>(); + String tag; + String customTag = classTags.get(javaBean.getClass()); + if (customTag == null) { + if (rootTag == null) { + tag = "tag:yaml.org,2002:" + javaBean.getClass().getName(); + } else { + tag = "tag:yaml.org,2002:map"; + } + } else { + tag = customTag; + } + if (rootTag == null) { + rootTag = tag; + } + // flow style will be chosen by BaseRepresenter + MappingNode node = new MappingNode(tag, value, null); + representedObjects.put(aliasKey, node); + boolean bestStyle = true; + for (Property property : properties) { + Node nodeKey = representData(property.getName()); + Object memberValue = property.get(javaBean); + Node nodeValue = representData(memberValue); + if (nodeValue instanceof MappingNode) { + if (!Map.class.isAssignableFrom(memberValue.getClass())) { + if (property.getType() != memberValue.getClass()) { + String memberTag = "tag:yaml.org,2002:" + memberValue.getClass().getName(); + nodeValue.setTag(memberTag); + } + } + } else if (memberValue != null && Enum.class.isAssignableFrom(memberValue.getClass())) { + nodeValue.setTag("tag:yaml.org,2002:str"); + } + if (!((nodeKey instanceof ScalarNode && ((ScalarNode) nodeKey).getStyle() == null))) { + bestStyle = false; + } + if (!((nodeValue instanceof ScalarNode && ((ScalarNode) nodeValue).getStyle() == null))) { + bestStyle = false; + } + value.add(new Node[] { nodeKey, nodeValue }); + } + if (defaultFlowStyle != null) { + node.setFlowStyle(defaultFlowStyle); + } else { + node.setFlowStyle(bestStyle); + } + return node; + } + + private Set<Property> getProperties(Class<? extends Object> type) throws IntrospectionException { + Set<Property> properties = new TreeSet<Property>(); + for (PropertyDescriptor property : Introspector.getBeanInfo(type).getPropertyDescriptors()) + if (property.getReadMethod() != null + && !property.getReadMethod().getName().equals("getClass")) { + properties.add(new MethodProperty(property)); + } + for (Field field : type.getFields()) { + int modifiers = field.getModifiers(); + if (!Modifier.isPublic(modifiers) || Modifier.isStatic(modifiers) + || Modifier.isTransient(modifiers)) + continue; + properties.add(new FieldProperty(field)); + } + return properties; + } +} diff --git a/src/main/java/org/yaml/snakeyaml/representer/SafeRepresenter.java b/src/main/java/org/yaml/snakeyaml/representer/SafeRepresenter.java new file mode 100644 index 00000000..77c4a8b2 --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/representer/SafeRepresenter.java @@ -0,0 +1,219 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.representer;
+
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TimeZone;
+import java.util.regex.Pattern;
+
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.util.Base64Coder;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+class SafeRepresenter extends BaseRepresenter {
+
+ public SafeRepresenter(Character default_style, Boolean default_flow_style) {
+ super(default_style, default_flow_style);
+ this.nullRepresenter = new RepresentNull();
+ this.representers.put(String.class, new RepresentString());
+ this.representers.put(Boolean.class, new RepresentBoolean());
+ this.representers.put(Character.class, new RepresentString());
+ this.representers.put(byte[].class, new RepresentByteArray());
+ this.multiRepresenters.put(Number.class, new RepresentNumber());
+ this.multiRepresenters.put(List.class, new RepresentList());
+ this.multiRepresenters.put(Map.class, new RepresentMap());
+ this.multiRepresenters.put(Set.class, new RepresentSet());
+ this.multiRepresenters.put(new Object[0].getClass(), new RepresentArray());
+ this.multiRepresenters.put(Date.class, new RepresentDate());
+ this.multiRepresenters.put(Enum.class, new RepresentEnum());
+ }
+
+ @Override
+ protected boolean ignoreAliases(Object data) {
+ if (data == null) {
+ return true;
+ }
+ if (data instanceof Object[]) {
+ Object[] array = (Object[]) data;
+ if (array.length == 0) {
+ return true;
+ }
+ }
+ return data instanceof String || data instanceof Boolean || data instanceof Integer
+ || data instanceof Long || data instanceof Float || data instanceof Double
+ || data instanceof Enum;
+ }
+
+ private class RepresentNull implements Represent {
+ public Node representData(Object data) {
+ return representScalar("tag:yaml.org,2002:null", "null");
+ }
+ }
+
+ public static Pattern BINARY_PATTERN = Pattern.compile("[\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F]");
+
+ private class RepresentString implements Represent {
+ public Node representData(Object data) {
+ String tag = "tag:yaml.org,2002:str";
+ Character style = null;
+ String value = data.toString();
+ if (BINARY_PATTERN.matcher(value).find()) {
+ tag = "tag:yaml.org,2002:binary";
+ char[] binary;
+ binary = Base64Coder.encode(value.getBytes());
+ value = String.valueOf(binary);
+ style = '|';
+ }
+ return representScalar(tag, value, style);
+ }
+ }
+
+ private class RepresentBoolean implements Represent {
+ public Node representData(Object data) {
+ String value;
+ if (Boolean.TRUE.equals(data)) {
+ value = "true";
+ } else {
+ value = "false";
+ }
+ return representScalar("tag:yaml.org,2002:bool", value);
+ }
+ }
+
+ private class RepresentNumber implements Represent {
+ public Node representData(Object data) {
+ String tag;
+ String value;
+ if (data instanceof Byte || data instanceof Short || data instanceof Integer
+ || data instanceof Long || data instanceof BigInteger) {
+ tag = "tag:yaml.org,2002:int";
+ value = data.toString();
+ } else {
+ Number number = (Number) data;
+ tag = "tag:yaml.org,2002:float";
+ if (number.equals(Double.NaN)) {
+ value = ".NaN";
+ } else if (number.equals(Double.POSITIVE_INFINITY)) {
+ value = ".inf";
+ } else if (number.equals(Double.NEGATIVE_INFINITY)) {
+ value = "-.inf";
+ } else {
+ value = number.toString();
+ }
+ }
+ return representScalar(tag, value);
+ }
+ }
+
+ private class RepresentList implements Represent {
+ @SuppressWarnings("unchecked")
+ public Node representData(Object data) {
+ return representSequence("tag:yaml.org,2002:seq", (List<Object>) data, null);
+ }
+ }
+
+ private class RepresentArray implements Represent {
+ public Node representData(Object data) {
+ Object[] array = (Object[]) data;
+ List<Object> list = Arrays.asList(array);
+ return representSequence("tag:yaml.org,2002:seq", list, null);
+ }
+ }
+
+ private class RepresentMap implements Represent {
+ @SuppressWarnings("unchecked")
+ public Node representData(Object data) {
+ return representMapping("tag:yaml.org,2002:map", (Map<Object, Object>) data, null);
+ }
+ }
+
+ private class RepresentSet implements Represent {
+ @SuppressWarnings("unchecked")
+ public Node representData(Object data) {
+ Map<Object, Object> value = new LinkedHashMap<Object, Object>();
+ Set<Object> set = (Set<Object>) data;
+ for (Object key : set) {
+ value.put(key, null);
+ }
+ return representMapping("tag:yaml.org,2002:set", value, null);
+ }
+ }
+
+ private class RepresentDate implements Represent {
+ public Node representData(Object data) {
+ // because SimpleDateFormat ignores timezone we have to use Calendar
+ Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
+ calendar.setTime((Date) data);
+ int years = calendar.get(Calendar.YEAR);
+ int months = calendar.get(Calendar.MONTH) + 1; // 0..12
+ int days = calendar.get(Calendar.DAY_OF_MONTH); // 1..31
+ int hour24 = calendar.get(Calendar.HOUR_OF_DAY); // 0..24
+ int minutes = calendar.get(Calendar.MINUTE); // 0..59
+ int seconds = calendar.get(Calendar.SECOND); // 0..59
+ int millis = calendar.get(Calendar.MILLISECOND);
+ StringBuffer buffer = new StringBuffer(String.valueOf(years));
+ buffer.append("-");
+ if (months < 10) {
+ buffer.append("0");
+ }
+ buffer.append(String.valueOf(months));
+ buffer.append("-");
+ if (days < 10) {
+ buffer.append("0");
+ }
+ buffer.append(String.valueOf(days));
+ buffer.append("T");
+ if (hour24 < 10) {
+ buffer.append("0");
+ }
+ buffer.append(String.valueOf(hour24));
+ buffer.append(":");
+ if (minutes < 10) {
+ buffer.append("0");
+ }
+ buffer.append(String.valueOf(minutes));
+ buffer.append(":");
+ if (seconds < 10) {
+ buffer.append("0");
+ }
+ buffer.append(String.valueOf(seconds));
+ if (millis > 0) {
+ if (millis < 10) {
+ buffer.append(".00");
+ } else if (millis < 100) {
+ buffer.append(".0");
+ } else {
+ buffer.append(".");
+ }
+ buffer.append(String.valueOf(millis));
+ }
+ buffer.append("Z");
+ return representScalar("tag:yaml.org,2002:timestamp", buffer.toString(), null);
+ }
+ }
+
+ private class RepresentEnum implements Represent {
+ public Node representData(Object data) {
+ String tag = "tag:yaml.org,2002:" + data.getClass().getName();
+ return representScalar(tag, data.toString());
+ }
+ }
+
+ private class RepresentByteArray implements Represent {
+ public Node representData(Object data) {
+ String tag = "tag:yaml.org,2002:binary";
+ char[] binary = Base64Coder.encode((byte[]) data);
+ return representScalar(tag, String.valueOf(binary), '|');
+ }
+ }
+}
\ No newline at end of file diff --git a/src/main/java/org/yaml/snakeyaml/resolver/RagelMachine.rl b/src/main/java/org/yaml/snakeyaml/resolver/RagelMachine.rl new file mode 100644 index 00000000..4a084426 --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/resolver/RagelMachine.rl @@ -0,0 +1,81 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.resolver;
+//Source for Ragel 6.3
+
+/**
+ * Generated by Ragel 6.3 (http://www.complang.org/ragel/)
+ * @see http://www.complang.org/ragel/
+ */
+public class RagelMachine {
+ %%{
+ machine snakeyaml;
+ action bool_tag { tag = "tag:yaml.org,2002:bool"; }
+ action merge_tag { tag = "tag:yaml.org,2002:merge"; }
+ action null_tag { tag = "tag:yaml.org,2002:null"; }
+ action value_tag { tag = "tag:yaml.org,2002:value"; }
+ action int_tag { tag = "tag:yaml.org,2002:int"; }
+ action float_tag { tag = "tag:yaml.org,2002:float"; }
+ action timestamp_tag { tag = "tag:yaml.org,2002:timestamp"; }
+
+ Bool = ("yes" | "Yes" | "YES" | "no" | "No" | "NO" |
+ "true" | "True" | "TRUE" | "false" | "False" | "FALSE" |
+ "on" | "On" | "ON" | "off" | "Off" | "OFF") %/bool_tag;
+ Merge = "<<" %/merge_tag;
+ Value = "=" %/value_tag;
+ Null = ("~" | "null" | "Null" | "NULL" | " ") %/null_tag;
+
+ sign = "-" | "+";
+ digit2 = digit | "_";
+ binaryInt = "0b" [0-1_]+;
+ octalInt = "0" [0-7_]+;
+ decimalInt = "0" | [1-9]digit2* (":" [0-5]? digit)*;
+ hexaInt = "0x" [0-9a-fA-F_]+;
+ Int = sign? (binaryInt | octalInt | decimalInt | hexaInt) %/int_tag;
+
+ exp = [eE] sign digit+;
+ Float = ((sign? ((digit+ digit2* "." digit2* exp?)
+ | ((digit+ digit2*)? "." digit+ digit2* exp?)
+ | (digit+ (":" [0-5]? digit)+ "." digit*)
+ | "." ("inf" | "Inf" | "INF")))
+ | ("." ("nan" | "NaN" | "NAN"))) %/float_tag;
+
+ TimestampShort = digit{4} ("-" digit{2}){2} %/timestamp_tag;
+ fract = "." digit*;
+ zone = [ \t]* ("Z" | (sign digit{1,2} ( ":" digit{2} )?));
+ Timestamp = digit{4} ("-" digit{1,2}){2} ([Tt] | [ \t]+)
+ digit{1,2} ":" digit{2} ":" digit{2} fract? zone? %/timestamp_tag;
+
+ Scalar = Bool | Null | Int | Float | TimestampShort | Merge | Value | Timestamp;
+ main := Scalar;
+ write data nofinal;
+ }%%
+
+ public String scan(String scalar) {
+ if (scalar == null) {
+ throw new NullPointerException("Scalar must be provided.");
+ }
+ String tag = null;
+ int cs = 0;
+ int p = 0;
+ int pe = scalar.length();
+ int eof = pe;
+ char[] data;
+ if (pe == 0) {
+ // NULL value
+ data = new char[] { '~' };
+ pe = 1;
+ eof = 1;
+ } else {
+ data = scalar.toCharArray();
+ }
+ %%{
+ # Initialize and execute.
+ write init;
+ write exec;
+ }%%
+
+ return tag;
+ }
+}
\ No newline at end of file diff --git a/src/main/java/org/yaml/snakeyaml/resolver/Resolver.java b/src/main/java/org/yaml/snakeyaml/resolver/Resolver.java new file mode 100644 index 00000000..2f578d04 --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/resolver/Resolver.java @@ -0,0 +1,114 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.resolver; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; + +import org.yaml.snakeyaml.nodes.NodeId; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public class Resolver { + private static final String DEFAULT_SCALAR_TAG = "tag:yaml.org,2002:str"; + private static final String DEFAULT_SEQUENCE_TAG = "tag:yaml.org,2002:seq"; + private static final String DEFAULT_MAPPING_TAG = "tag:yaml.org,2002:map"; + private static final Pattern BOOL = Pattern + .compile("^(?:yes|Yes|YES|no|No|NO|true|True|TRUE|false|False|FALSE|on|On|ON|off|Off|OFF)$"); + private static final Pattern FLOAT = Pattern + .compile("^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?|[-+]?(?:[0-9][0-9_]*)?\\.[0-9_]+(?:[eE][-+][0-9]+)?|[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*|[-+]?\\.(?:inf|Inf|INF)|\\.(?:nan|NaN|NAN))$"); + private static final Pattern INT = Pattern + .compile("^(?:[-+]?0b[0-1_]+|[-+]?0[0-7_]+|[-+]?(?:0|[1-9][0-9_]*)|[-+]?0x[0-9a-fA-F_]+|[-+]?[1-9][0-9_]*(?::[0-5]?[0-9])+)$"); + private static final Pattern MERGE = Pattern.compile("^(?:<<)$"); + private static final Pattern NULL = Pattern.compile("^(?:~|null|Null|NULL| )$"); + private static final Pattern EMPTY = Pattern.compile("^$"); + private static final Pattern TIMESTAMP = Pattern + .compile("^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]|[0-9][0-9][0-9][0-9]-[0-9][0-9]?-[0-9][0-9]?(?:[Tt]|[ \t]+)[0-9][0-9]?:[0-9][0-9]:[0-9][0-9](?:\\.[0-9]*)?(?:[ \t]*(?:Z|[-+][0-9][0-9]?(?::[0-9][0-9])?))?)$"); + private static final Pattern VALUE = Pattern.compile("^(?:=)$"); + private static final Pattern YAML = Pattern.compile("^(?:!|&|\\*)$"); + + private Map<Character, List<ResolverTuple>> yamlImplicitResolvers = new HashMap<Character, List<ResolverTuple>>(); + + public Resolver() { + addImplicitResolver("tag:yaml.org,2002:bool", BOOL, "yYnNtTfFoO"); + addImplicitResolver("tag:yaml.org,2002:float", FLOAT, "-+0123456789."); + addImplicitResolver("tag:yaml.org,2002:int", INT, "-+0123456789"); + addImplicitResolver("tag:yaml.org,2002:merge", MERGE, "<"); + addImplicitResolver("tag:yaml.org,2002:null", NULL, "~nN\0"); + addImplicitResolver("tag:yaml.org,2002:null", EMPTY, null); + addImplicitResolver("tag:yaml.org,2002:timestamp", TIMESTAMP, "0123456789"); + addImplicitResolver("tag:yaml.org,2002:value", VALUE, "="); + // The following implicit resolver is only for documentation purposes. + // It cannot work + // because plain scalars cannot start with '!', '&', or '*'. + addImplicitResolver("tag:yaml.org,2002:yaml", YAML, "!&*"); + } + + public void addImplicitResolver(String tag, Pattern regexp, String first) { + if (first == null) { + List<ResolverTuple> curr = yamlImplicitResolvers.get(null); + if (curr == null) { + curr = new LinkedList<ResolverTuple>(); + yamlImplicitResolvers.put(null, curr); + } + curr.add(new ResolverTuple(tag, regexp)); + } else { + char[] chrs = first.toCharArray(); + for (int i = 0, j = chrs.length; i < j; i++) { + Character theC = new Character(chrs[i]); + if (theC == 0) { + // special case: for null + theC = null; + } + List<ResolverTuple> curr = yamlImplicitResolvers.get(theC); + if (curr == null) { + curr = new LinkedList<ResolverTuple>(); + yamlImplicitResolvers.put(theC, curr); + } + curr.add(new ResolverTuple(tag, regexp)); + } + } + } + + public String resolve(NodeId kind, String value, boolean implicit) { + if (kind == NodeId.scalar && implicit) { + List<ResolverTuple> resolvers = null; + if ("".equals(value)) { + resolvers = yamlImplicitResolvers.get('\0'); + } else { + resolvers = yamlImplicitResolvers.get(value.charAt(0)); + } + if (resolvers != null) { + for (ResolverTuple v : resolvers) { + String tag = v.getTag(); + Pattern regexp = v.getRegexp(); + if (regexp.matcher(value).matches()) { + return tag; + } + } + } + if (yamlImplicitResolvers.containsKey(null)) { + for (ResolverTuple v : yamlImplicitResolvers.get(null)) { + String tag = v.getTag(); + Pattern regexp = v.getRegexp(); + if (regexp.matcher(value).matches()) { + return tag; + } + } + } + } + switch (kind) { + case scalar: + return DEFAULT_SCALAR_TAG; + case sequence: + return DEFAULT_SEQUENCE_TAG; + default: + return DEFAULT_MAPPING_TAG; + } + } +}
\ No newline at end of file diff --git a/src/main/java/org/yaml/snakeyaml/resolver/ResolverTuple.java b/src/main/java/org/yaml/snakeyaml/resolver/ResolverTuple.java new file mode 100644 index 00000000..239e51ae --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/resolver/ResolverTuple.java @@ -0,0 +1,29 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.resolver;
+
+import java.util.regex.Pattern;
+
+final class ResolverTuple {
+ private final String tag;
+ private final Pattern regexp;
+
+ public ResolverTuple(String tag, Pattern regexp) {
+ this.tag = tag;
+ this.regexp = regexp;
+ }
+
+ public String getTag() {
+ return tag;
+ }
+
+ public Pattern getRegexp() {
+ return regexp;
+ }
+
+ @Override
+ public String toString() {
+ return "Tuple tag=" + tag + " regexp=" + regexp;
+ }
+}
\ No newline at end of file diff --git a/src/main/java/org/yaml/snakeyaml/scanner/Scanner.java b/src/main/java/org/yaml/snakeyaml/scanner/Scanner.java new file mode 100644 index 00000000..6ed91ab8 --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/scanner/Scanner.java @@ -0,0 +1,36 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.scanner; + +import java.util.List; + +import org.yaml.snakeyaml.tokens.Token; + +/** + * Produce <code>Token<code>s. + * + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public interface Scanner { + /** + * Check if the next token is one of the given types. + */ + boolean checkToken(List<Class<? extends Token>> choices); + + /** + * Convenience method to avoid List creation + */ + boolean checkToken(Class<? extends Token> choice); + + /** + * Return the next token, but do not delete it from the queue. + */ + Token peekToken(); + + /** + * Return the next token. + */ + Token getToken(); + +} diff --git a/src/main/java/org/yaml/snakeyaml/scanner/ScannerException.java b/src/main/java/org/yaml/snakeyaml/scanner/ScannerException.java new file mode 100644 index 00000000..3dbae586 --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/scanner/ScannerException.java @@ -0,0 +1,25 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.scanner; + +import org.yaml.snakeyaml.error.Mark; +import org.yaml.snakeyaml.error.MarkedYAMLException; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public class ScannerException extends MarkedYAMLException { + + private static final long serialVersionUID = 4782293188600445954L; + + public ScannerException(String context, Mark contextMark, String problem, Mark problemMark, + String note) { + super(context, contextMark, problem, problemMark, note); + } + + public ScannerException(String context, Mark contextMark, String problem, Mark problemMark) { + super(context, contextMark, problem, problemMark, null); + } + +} diff --git a/src/main/java/org/yaml/snakeyaml/scanner/ScannerImpl.java b/src/main/java/org/yaml/snakeyaml/scanner/ScannerImpl.java new file mode 100644 index 00000000..9941ce73 --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/scanner/ScannerImpl.java @@ -0,0 +1,1757 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.scanner; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.regex.Pattern; + +import org.yaml.snakeyaml.error.Mark; +import org.yaml.snakeyaml.error.YAMLException; +import org.yaml.snakeyaml.tokens.AliasToken; +import org.yaml.snakeyaml.tokens.AnchorToken; +import org.yaml.snakeyaml.tokens.BlockEndToken; +import org.yaml.snakeyaml.tokens.BlockEntryToken; +import org.yaml.snakeyaml.tokens.BlockMappingStartToken; +import org.yaml.snakeyaml.tokens.BlockSequenceStartToken; +import org.yaml.snakeyaml.tokens.DirectiveToken; +import org.yaml.snakeyaml.tokens.DocumentEndToken; +import org.yaml.snakeyaml.tokens.DocumentStartToken; +import org.yaml.snakeyaml.tokens.FlowEntryToken; +import org.yaml.snakeyaml.tokens.FlowMappingEndToken; +import org.yaml.snakeyaml.tokens.FlowMappingStartToken; +import org.yaml.snakeyaml.tokens.FlowSequenceEndToken; +import org.yaml.snakeyaml.tokens.FlowSequenceStartToken; +import org.yaml.snakeyaml.tokens.KeyToken; +import org.yaml.snakeyaml.tokens.ScalarToken; +import org.yaml.snakeyaml.tokens.StreamEndToken; +import org.yaml.snakeyaml.tokens.StreamStartToken; +import org.yaml.snakeyaml.tokens.TagToken; +import org.yaml.snakeyaml.tokens.Token; +import org.yaml.snakeyaml.tokens.ValueToken; + +/** + * <pre> + * Scanner produces tokens of the following types: + * STREAM-START + * STREAM-END + * DIRECTIVE(name, value) + * DOCUMENT-START + * DOCUMENT-END + * BLOCK-SEQUENCE-START + * BLOCK-MAPPING-START + * BLOCK-END + * FLOW-SEQUENCE-START + * FLOW-MAPPING-START + * FLOW-SEQUENCE-END + * FLOW-MAPPING-END + * BLOCK-ENTRY + * FLOW-ENTRY + * KEY + * VALUE + * ALIAS(value) + * ANCHOR(value) + * TAG(value) + * SCALAR(value, plain, style) + * Read comments in the Scanner code for more details. + * </pre> + * + * Reader does the dirty work of checking for BOM and converting the input data + * to Unicode. It also adds NUL to the end. + * + * Reader supports the following methods + * + * <pre> + * reader.peek(i=0) # peek the next i-th character self.prefix(l=1) + * reader.peek the next l characters + * reader.forward(l=1) read the next l characters and move the pointer. + * </pre> + */ +public final class ScannerImpl implements Scanner { + private final static String NULL_BL_LINEBR = "\0 \r\n\u0085\u2028\u2029"; + private final static String NULL_BL_T_LINEBR = "\0 \t\r\n\u0085\u2028\u2029"; + public final static String NULL_OR_LINEBR = "\0\r\n\u0085\u2028\u2029"; + private final static String FULL_LINEBR = "\r\n\u0085\u2028\u2029"; + private final static String ALPHA = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-_"; + private final static Pattern NOT_HEXA = Pattern.compile("[^0-9A-Fa-f]"); + public final static Map<Character, String> ESCAPE_REPLACEMENTS = new HashMap<Character, String>(); + public final static Map<Character, Integer> ESCAPE_CODES = new HashMap<Character, Integer>(); + + static { + ESCAPE_REPLACEMENTS.put(new Character('0'), "\0"); + ESCAPE_REPLACEMENTS.put(new Character('a'), "\u0007"); + ESCAPE_REPLACEMENTS.put(new Character('b'), "\u0008"); + ESCAPE_REPLACEMENTS.put(new Character('t'), "\u0009"); + ESCAPE_REPLACEMENTS.put(new Character('n'), "\n"); + ESCAPE_REPLACEMENTS.put(new Character('v'), "\u000B"); + ESCAPE_REPLACEMENTS.put(new Character('f'), "\u000C"); + ESCAPE_REPLACEMENTS.put(new Character('r'), "\r"); + ESCAPE_REPLACEMENTS.put(new Character('e'), "\u001B"); + ESCAPE_REPLACEMENTS.put(new Character(' '), "\u0020"); + ESCAPE_REPLACEMENTS.put(new Character('"'), "\""); + ESCAPE_REPLACEMENTS.put(new Character('\\'), "\\"); + ESCAPE_REPLACEMENTS.put(new Character('N'), "\u0085"); + ESCAPE_REPLACEMENTS.put(new Character('_'), "\u00A0"); + ESCAPE_REPLACEMENTS.put(new Character('L'), "\u2028"); + ESCAPE_REPLACEMENTS.put(new Character('P'), "\u2029"); + + ESCAPE_CODES.put(new Character('x'), new Integer(2)); + ESCAPE_CODES.put(new Character('u'), new Integer(4)); + ESCAPE_CODES.put(new Character('U'), new Integer(8)); + } + private final org.yaml.snakeyaml.reader.Reader reader; + // Had we reached the end of the stream? + private boolean done = false; + + // The number of unclosed '{' and '['. `flow_level == 0` means block + // context. + private int flowLevel = 0; + + // List of processed tokens that are not yet emitted. + private List<Token> tokens; + + // Number of tokens that were emitted through the `get_token` method. + private int tokensTaken = 0; + + // The current indentation level. + private int indent = -1; + + // Past indentation levels. + private LinkedList<Integer> indents; + + // Variables related to simple keys treatment. See PyYAML. + + /** + * <pre> + * A simple key is a key that is not denoted by the '?' indicator. + * Example of simple keys: + * --- + * block simple key: value + * ? not a simple key: + * : { flow simple key: value } + * We emit the KEY token before all keys, so when we find a potential + * simple key, we try to locate the corresponding ':' indicator. + * Simple keys should be limited to a single line and 1024 characters. + * + * Can a simple key start at the current position? A simple key may + * start: + * - at the beginning of the line, not counting indentation spaces + * (in block context), + * - after '{', '[', ',' (in the flow context), + * - after '?', ':', '-' (in the block context). + * In the block context, this flag also signifies if a block collection + * may start at the current position. + * </pre> + */ + private boolean allowSimpleKey = true; + + /* + * Keep track of possible simple keys. This is a dictionary. The key is + * `flow_level`; there can be no more that one possible simple key for each + * level. The value is a SimpleKey record: (token_number, required, index, + * line, column, mark) A simple key may start with ALIAS, ANCHOR, TAG, + * SCALAR(flow), '[', or '{' tokens. + */ + private Map<Integer, SimpleKey> possibleSimpleKeys; + + public ScannerImpl(org.yaml.snakeyaml.reader.Reader reader) { + this.reader = reader; + this.tokens = new LinkedList<Token>(); + this.indents = new LinkedList<Integer>(); + // the order in possibleSimpleKeys is kept for nextPossibleSimpleKey() + this.possibleSimpleKeys = new LinkedHashMap<Integer, SimpleKey>(); + fetchStreamStart();// Add the STREAM-START token. + } + + /** + * Check if the next token is one of the given types. + */ + public boolean checkToken(List<Class<? extends Token>> choices) { + while (needMoreTokens()) { + fetchMoreTokens(); + } + if (!this.tokens.isEmpty()) { + if (choices.size() == 0) { + return true; + } + Token first = this.tokens.get(0); + for (Class<? extends Token> class1 : choices) { + if (class1.isInstance(first)) { + return true; + } + } + } + return false; + } + + /** + * Check if the next token is one of the given types. + */ + public boolean checkToken(Class<? extends Token> choice) { + List<Class<? extends Token>> list = new ArrayList<Class<? extends Token>>(); + list.add(choice); + return checkToken(list); + } + + /** + * Return the next token, but do not delete if from the queue. + */ + public Token peekToken() { + while (needMoreTokens()) { + fetchMoreTokens(); + } + return this.tokens.get(0); + } + + /** + * Return the next token. + */ + public Token getToken() { + if (!this.tokens.isEmpty()) { + this.tokensTaken++; + return this.tokens.remove(0); + } + return null; + } + + // Private methods. + + private boolean needMoreTokens() { + if (this.done) { + return false; + } + if (this.tokens.isEmpty()) { + return true; + } + // The current token may be a potential simple key, so we + // need to look further. + stalePossibleSimpleKeys(); + return nextPossibleSimpleKey() == this.tokensTaken; + } + + private void fetchMoreTokens() { + // Eat whitespaces and comments until we reach the next token. + scanToNextToken(); + // Remove obsolete possible simple keys. + stalePossibleSimpleKeys(); + // Compare the current indentation and column. It may add some tokens + // and decrease the current indentation level. + unwindIndent(reader.getColumn()); + // Peek the next character. + char ch = reader.peek(); + switch (ch) { + case '\0': + // Is it the end of stream? + fetchStreamEnd(); + return; + case '%': + // Is it a directive? + if (checkDirective()) { + fetchDirective(); + return; + } + break; + case '-': + // Is it the document start? + if (checkDocumentStart()) { + fetchDocumentStart(); + return; + // Is it the block entry indicator? + } else if (checkBlockEntry()) { + fetchBlockEntry(); + return; + } + break; + case '.': + // Is it the document end? + if (checkDocumentEnd()) { + fetchDocumentEnd(); + return; + } + break; + // TODO support for BOM within a stream. (not implemented in PyYAML) + case '[': + // Is it the flow sequence start indicator? + fetchFlowSequenceStart(); + return; + case '{': + // Is it the flow mapping start indicator? + fetchFlowMappingStart(); + return; + case ']': + // Is it the flow sequence end indicator? + fetchFlowSequenceEnd(); + return; + case '}': + // Is it the flow mapping end indicator? + fetchFlowMappingEnd(); + return; + case ',': + // Is it the flow entry indicator? + fetchFlowEntry(); + return; + // see block entry indicator above + case '?': + // Is it the key indicator? + if (checkKey()) { + fetchKey(); + return; + } + break; + case ':': + // Is it the value indicator? + if (checkValue()) { + fetchValue(); + return; + } + break; + case '*': + // Is it an alias? + fetchAlias(); + return; + case '&': + // Is it an anchor? + fetchAnchor(); + return; + case '!': + // Is it a tag? + fetchTag(); + return; + case '|': + // Is it a literal scalar? + if (this.flowLevel == 0) { + fetchLiteral(); + return; + } + break; + case '>': + // Is it a folded scalar? + if (this.flowLevel == 0) { + fetchFolded(); + return; + } + break; + case '\'': + // Is it a single quoted scalar? + fetchSingle(); + return; + case '"': + // Is it a double quoted scalar? + fetchDouble(); + return; + } + // It must be a plain scalar then. + if (checkPlain()) { + fetchPlain(); + return; + } + // No? It's an error. Let's produce a nice error message. + throw new ScannerException("while scanning for the next token", null, "found character " + + ch + "(" + ((int) ch) + " that cannot start any token", reader.getMark()); + } + + // Simple keys treatment. + + /** + * Return the number of the nearest possible simple key. Actually we don't + * need to loop through the whole dictionary. + */ + private int nextPossibleSimpleKey() { + /* + * the implementation is not as in PyYAML. Because + * this.possibleSimpleKeys is ordered we can simply take the first key + */ + Iterator<SimpleKey> iter = this.possibleSimpleKeys.values().iterator(); + if (iter.hasNext()) { + SimpleKey key = iter.next(); + return key.getTokenNumber(); + } + return -1; + } + + /** + * <pre> + * Remove entries that are no longer possible simple keys. According to + * the YAML specification, simple keys + * - should be limited to a single line, + * - should be no longer than 1024 characters. + * Disabling this procedure will allow simple keys of any length and + * height (may cause problems if indentation is broken though). + * </pre> + */ + private void stalePossibleSimpleKeys() { + // use toRemove to avoid java.util.ConcurrentModificationException + Set<Integer> toRemove = null; + for (Integer level : this.possibleSimpleKeys.keySet()) { + SimpleKey key = this.possibleSimpleKeys.get(level); + if ((key.getLine() != reader.getLine()) || (reader.getIndex() - key.getIndex() > 1024)) { + if (key.isRequired()) { + throw new ScannerException("while scanning a simple key", key.getMark(), + "could not found expected ':'", reader.getMark()); + } else { + if (toRemove == null) { + toRemove = new HashSet<Integer>(); + } + toRemove.add(level); + } + } + } + if (toRemove != null) { + for (Integer level : toRemove) { + this.possibleSimpleKeys.remove(level); + } + } + } + + /** + * The next token may start a simple key. We check if it's possible and save + * its position. This function is called for ALIAS, ANCHOR, TAG, + * SCALAR(flow), '[', and '{'. + */ + private void savePossibleSimpleKey() { + // The next token may start a simple key. We check if it's possible + // and save its position. This function is called for + // ALIAS, ANCHOR, TAG, SCALAR(flow), '[', and '{'. + + // Check if a simple key is required at the current position. + boolean required = ((this.flowLevel == 0) && (this.indent == this.reader.getColumn())); + + if (allowSimpleKey || !required) { + // A simple key is required only if it is the first token in the + // current + // line. Therefore it is always allowed. + } else { + throw new YAMLException( + "A simple key is required only if it is the first token in the current line"); + } + + // The next token might be a simple key. Let's save it's number and + // position. + if (this.allowSimpleKey) { + removePossibleSimpleKey(); + int tokenNumber = this.tokensTaken + this.tokens.size(); + SimpleKey key = new SimpleKey(tokenNumber, required, reader.getIndex(), reader + .getLine(), this.reader.getColumn(), this.reader.getMark()); + this.possibleSimpleKeys.put(new Integer(this.flowLevel), key); + } + } + + /** + * Remove the saved possible key position at the current flow level. + */ + private void removePossibleSimpleKey() { + if (this.possibleSimpleKeys.keySet().contains(new Integer(flowLevel))) { + SimpleKey key = possibleSimpleKeys.get(new Integer(flowLevel)); + if (key.isRequired()) { + throw new ScannerException("while scanning a simple key", key.getMark(), + "could not found expected ':'", reader.getMark()); + } + possibleSimpleKeys.remove(flowLevel); + } + } + + // Indentation functions. + + /** + * <pre> + * In flow context, tokens should respect indentation. + * Actually the condition should be `self.indent >= column` according to + * the spec. But this condition will prohibit intuitively correct + * constructions such as + * key : { + * } + * </pre> + */ + private void unwindIndent(int col) { + // In the flow context, indentation is ignored. We make the scanner less + // restrictive then specification requires. + if (this.flowLevel != 0) { + return; + } + + // In block context, we may need to issue the BLOCK-END tokens. + while (this.indent > col) { + Mark mark = reader.getMark(); + this.indent = this.indents.removeFirst(); + this.tokens.add(new BlockEndToken(mark, mark)); + } + } + + /** + * Check if we need to increase indentation. + */ + private boolean addIndent(int column) { + if (this.indent < column) { + this.indents.addFirst(this.indent); + this.indent = column; + return true; + } + return false; + } + + // Fetchers. + + /** + * We always add STREAM-START as the first token and STREAM-END as the last + * token. + */ + private void fetchStreamStart() { + // Read the token. + Mark mark = reader.getMark(); + + // Add STREAM-START. + Token token = new StreamStartToken(mark, mark); + this.tokens.add(token); + } + + private void fetchStreamEnd() { + // Set the current intendation to -1. + unwindIndent(-1); + + // Reset everything (not really needed). + this.allowSimpleKey = false; + this.possibleSimpleKeys = new HashMap<Integer, SimpleKey>(); + + // Read the token. + Mark mark = reader.getMark(); + + // Add STREAM-END. + Token token = new StreamEndToken(mark, mark); + this.tokens.add(token); + + // The stream is finished. + this.done = true; + } + + private void fetchDirective() { + // Set the current intendation to -1. + unwindIndent(-1); + + // Reset simple keys. + removePossibleSimpleKey(); + this.allowSimpleKey = false; + + // Scan and add DIRECTIVE. + Token tok = scanDirective(); + this.tokens.add(tok); + } + + private void fetchDocumentStart() { + fetchDocumentIndicator(true); + } + + private void fetchDocumentEnd() { + fetchDocumentIndicator(false); + } + + private void fetchDocumentIndicator(boolean isDocumentStart) { + // Set the current intendation to -1. + unwindIndent(-1); + + // Reset simple keys. Note that there could not be a block collection + // after '---'. + removePossibleSimpleKey(); + this.allowSimpleKey = false; + + // Add DOCUMENT-START or DOCUMENT-END. + Mark startMark = reader.getMark(); + reader.forward(3); + Mark endMark = reader.getMark(); + Token token; + if (isDocumentStart) { + token = new DocumentStartToken(startMark, endMark); + } else { + token = new DocumentEndToken(startMark, endMark); + } + this.tokens.add(token); + } + + private void fetchFlowSequenceStart() { + fetchFlowCollectionStart(false); + } + + private void fetchFlowMappingStart() { + fetchFlowCollectionStart(true); + } + + private void fetchFlowCollectionStart(boolean isMappingStart) { + // '[' and '{' may start a simple key. + savePossibleSimpleKey(); + + // Increase the flow level. + this.flowLevel++; + + // Simple keys are allowed after '[' and '{'. + this.allowSimpleKey = true; + + // Add FLOW-SEQUENCE-START or FLOW-MAPPING-START. + Mark startMark = reader.getMark(); + reader.forward(1); + Mark endMark = reader.getMark(); + Token token; + if (isMappingStart) { + token = new FlowMappingStartToken(startMark, endMark); + } else { + token = new FlowSequenceStartToken(startMark, endMark); + } + this.tokens.add(token); + } + + private void fetchFlowSequenceEnd() { + fetchFlowCollectionEnd(false); + } + + private void fetchFlowMappingEnd() { + fetchFlowCollectionEnd(true); + } + + private void fetchFlowCollectionEnd(boolean isMappingEnd) { + // Reset possible simple key on the current level. + removePossibleSimpleKey(); + + // Decrease the flow level. + this.flowLevel--; + + // No simple keys after ']' or '}'. + this.allowSimpleKey = false; + + // Add FLOW-SEQUENCE-END or FLOW-MAPPING-END. + Mark startMark = reader.getMark(); + reader.forward(); + Mark endMark = reader.getMark(); + Token token; + if (isMappingEnd) { + token = new FlowMappingEndToken(startMark, endMark); + } else { + token = new FlowSequenceEndToken(startMark, endMark); + } + this.tokens.add(token); + } + + private void fetchFlowEntry() { + // Simple keys are allowed after ','. + this.allowSimpleKey = true; + + // Reset possible simple key on the current level. + removePossibleSimpleKey(); + + // Add FLOW-ENTRY. + Mark startMark = reader.getMark(); + reader.forward(); + Mark endMark = reader.getMark(); + Token token = new FlowEntryToken(startMark, endMark); + this.tokens.add(token); + } + + private void fetchBlockEntry() { + // Block context needs additional checks. + if (this.flowLevel == 0) { + // Are we allowed to start a new entry? + if (!this.allowSimpleKey) { + throw new ScannerException(null, null, "sequence entries are not allowed here", + reader.getMark()); + } + + // We may need to add BLOCK-SEQUENCE-START. + if (addIndent(this.reader.getColumn())) { + Mark mark = reader.getMark(); + this.tokens.add(new BlockSequenceStartToken(mark, mark)); + } + } else { + // It's an error for the block entry to occur in the flow + // context,but we let the parser detect this. + } + // Simple keys are allowed after '-'. + this.allowSimpleKey = true; + + // Reset possible simple key on the current level. + removePossibleSimpleKey(); + + // Add BLOCK-ENTRY. + Mark startMark = reader.getMark(); + reader.forward(); + Mark endMark = reader.getMark(); + Token token = new BlockEntryToken(startMark, endMark); + this.tokens.add(token); + } + + private void fetchKey() { + // Block context needs additional checks. + if (this.flowLevel == 0) { + // Are we allowed to start a key (not necessary a simple)? + if (!this.allowSimpleKey) { + throw new ScannerException(null, null, "mapping keys are not allowed here", reader + .getMark()); + } + // We may need to add BLOCK-MAPPING-START. + if (addIndent(this.reader.getColumn())) { + Mark mark = reader.getMark(); + this.tokens.add(new BlockMappingStartToken(mark, mark)); + } + } + // Simple keys are allowed after '?' in the block context. + this.allowSimpleKey = this.flowLevel == 0; + + // Reset possible simple key on the current level. + removePossibleSimpleKey(); + + // Add KEY. + Mark startMark = reader.getMark(); + reader.forward(); + Mark endMark = reader.getMark(); + Token token = new KeyToken(startMark, endMark); + this.tokens.add(token); + } + + private void fetchValue() { + // Do we determine a simple key? + if (this.possibleSimpleKeys.keySet().contains(this.flowLevel)) { + // Add KEY. + SimpleKey key = this.possibleSimpleKeys.get(this.flowLevel); + this.possibleSimpleKeys.remove(this.flowLevel); + this.tokens.add(key.getTokenNumber() - this.tokensTaken, new KeyToken(key.getMark(), + key.getMark())); + + // If this key starts a new block mapping, we need to add + // BLOCK-MAPPING-START. + if (this.flowLevel == 0) { + if (addIndent(key.getColumn())) { + this.tokens.add(key.getTokenNumber() - this.tokensTaken, + new BlockMappingStartToken(key.getMark(), key.getMark())); + } + } + // There cannot be two simple keys one after another. + this.allowSimpleKey = false; + + } else {// It must be a part of a complex key. + // Block context needs additional checks.Do we really need them? + // They + // will be catched by the parser anyway.) + if (this.flowLevel == 0) { + + // We are allowed to start a complex value if and only if we can + // start a simple key. + if (!this.allowSimpleKey) { + throw new ScannerException(null, null, "mapping values are not allowed here", + reader.getMark()); + } + } + + // If this value starts a new block mapping, we need to add + // BLOCK-MAPPING-START. It will be detected as an error later by + // the parser. + if (flowLevel == 0) { + if (addIndent(reader.getColumn())) { + Mark mark = reader.getMark(); + this.tokens.add(new BlockMappingStartToken(mark, mark)); + } + } + + // Simple keys are allowed after ':' in the block context. + allowSimpleKey = (flowLevel == 0); + + // Reset possible simple key on the current level. + removePossibleSimpleKey(); + } + // Add VALUE. + Mark startMark = reader.getMark(); + reader.forward(); + Mark endMark = reader.getMark(); + Token token = new ValueToken(startMark, endMark); + this.tokens.add(token); + } + + private void fetchAlias() { + // ALIAS could be a simple key. + savePossibleSimpleKey(); + + // No simple keys after ALIAS. + this.allowSimpleKey = false; + + // Scan and add ALIAS. + Token tok = scanAnchor(false); + this.tokens.add(tok); + } + + private void fetchAnchor() { + // ANCHOR could start a simple key. + savePossibleSimpleKey(); + + // No simple keys after ANCHOR. + this.allowSimpleKey = false; + + // Scan and add ANCHOR. + Token tok = scanAnchor(true); + this.tokens.add(tok); + } + + private void fetchTag() { + // TAG could start a simple key. + savePossibleSimpleKey(); + + // No simple keys after TAG. + this.allowSimpleKey = false; + + // Scan and add TAG. + Token tok = scanTag(); + this.tokens.add(tok); + } + + private void fetchLiteral() { + fetchBlockScalar('|'); + } + + private void fetchFolded() { + fetchBlockScalar('>'); + } + + private void fetchBlockScalar(char style) { + // A simple key may follow a block scalar. + this.allowSimpleKey = true; + + // Reset possible simple key on the current level. + removePossibleSimpleKey(); + + // Scan and add SCALAR. + Token tok = scanBlockScalar(style); + this.tokens.add(tok); + } + + private void fetchSingle() { + fetchFlowScalar('\''); + } + + private void fetchDouble() { + fetchFlowScalar('"'); + } + + private void fetchFlowScalar(char style) { + // A flow scalar could be a simple key. + savePossibleSimpleKey(); + + // No simple keys after flow scalars. + this.allowSimpleKey = false; + + // Scan and add SCALAR. + Token tok = scanFlowScalar(style); + this.tokens.add(tok); + } + + private void fetchPlain() { + // A plain scalar could be a simple key. + savePossibleSimpleKey(); + + // No simple keys after plain scalars. But note that `scan_plain` will + // change this flag if the scan is finished at the beginning of the + // line. + this.allowSimpleKey = false; + + // Scan and add SCALAR. May change `allow_simple_key`. + Token tok = scanPlain(); + this.tokens.add(tok); + } + + // Checkers. + + private boolean checkDirective() { + // DIRECTIVE: ^ '%' ... + // The '%' indicator is already checked. + if (reader.getColumn() == 0) { + return true; + } else { + return false; + } + } + + private static final String SPACES = "\0 \t\r\n\u0085\u2028\u2029"; + + private boolean checkDocumentStart() { + // DOCUMENT-START: ^ '---' (' '|'\n') + if (reader.getColumn() == 0) { + if ("---".equals(reader.prefix(3)) && SPACES.indexOf(reader.peek(3)) != -1) { + return true; + } + } + return false; + } + + private boolean checkDocumentEnd() { + // DOCUMENT-END: ^ '...' (' '|'\n') + if (reader.getColumn() == 0) { + if ("...".equals(reader.prefix(3)) && SPACES.indexOf(reader.peek(3)) != -1) { + return true; + } + } + return false; + } + + private boolean checkBlockEntry() { + // BLOCK-ENTRY: '-' (' '|'\n') + return SPACES.indexOf(reader.peek(1)) != -1; + } + + private boolean checkKey() { + // KEY(flow context): '?' + if (this.flowLevel != 0) { + return true; + } else { + // KEY(block context): '?' (' '|'\n') + return SPACES.indexOf(reader.peek(1)) != -1; + } + } + + private boolean checkValue() { + // VALUE(flow context): ':' + if (flowLevel != 0) { + return true; + } else { + // VALUE(block context): ':' (' '|'\n') + return (SPACES.indexOf(reader.peek(1)) != -1); + } + } + + private boolean checkPlain() { + /** + * <pre> + * A plain scalar may start with any non-space character except: + * '-', '?', ':', ',', '[', ']', '{', '}', + * '#', '&', '*', '!', '|', '>', '\'', '\"', + * '%', '@', '`'. + * + * It may also start with + * '-', '?', ':' + * if it is followed by a non-space character. + * + * Note that we limit the last rule to the block context (except the + * '-' character) because we want the flow context to be space + * independent. + * </pre> + */ + char ch = reader.peek(); + return ("\0 \t\r\n\u0085\u2028\u2029-?:,[]{}#&*!|>\'\"%@`".indexOf(ch) == -1 || ("\0 \t\r\n\u0085\u2028\u2029" + .indexOf(reader.peek(1)) == -1 && (ch == '-' || (this.flowLevel == 0 && "?:" + .indexOf(ch) != -1)))); + } + + // Scanners. + + /** + * <pre> + * We ignore spaces, line breaks and comments. + * If we find a line break in the block context, we set the flag + * `allow_simple_key` on. + * The byte order mark is stripped if it's the first character in the + * stream. We do not yet support BOM inside the stream as the + * specification requires. Any such mark will be considered as a part + * of the document. + * TODO: We need to make tab handling rules more sane. A good rule is + * Tabs cannot precede tokens + * BLOCK-SEQUENCE-START, BLOCK-MAPPING-START, BLOCK-END, + * KEY(block), VALUE(block), BLOCK-ENTRY + * So the checking code is + * if <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 (reader.getIndex() == 0 && reader.peek() == '\uFEFF') { + reader.forward(); + } + boolean found = false; + while (!found) { + while (reader.peek() == ' ') { + reader.forward(); + } + if (reader.peek() == '#') { + while ("\0\r\n\u0085\u2028\u2029".indexOf(reader.peek()) == -1) { + reader.forward(); + } + } + if (scanLineBreak().length() != 0) { + if (this.flowLevel == 0) { + this.allowSimpleKey = true; + } + } else { + found = true; + } + } + } + + private Token scanDirective() { + // See the specification for details. + Mark startMark = reader.getMark(); + Mark endMark; + reader.forward(); + String name = scanDirectiveName(startMark); + List<?> value = null; + if (name.equals("YAML")) { + value = scanYamlDirectiveValue(startMark); + endMark = reader.getMark(); + } else if (name.equals("TAG")) { + value = scanTagDirectiveValue(startMark); + endMark = reader.getMark(); + } else { + endMark = reader.getMark(); + while ("\0\r\n\u0085\u2028\u2029".indexOf(reader.peek()) == -1) { + reader.forward(); + } + } + scanDirectiveIgnoredLine(startMark); + return new DirectiveToken(name, value, startMark, endMark); + } + + private String scanDirectiveName(Mark startMark) { + // See the specification for details. + int length = 0; + char ch = reader.peek(length); + while (ALPHA.indexOf(ch) != -1) { + length++; + ch = reader.peek(length); + } + if (length == 0) { + throw new ScannerException("while scanning a directive", startMark, + "expected alphabetic or numeric character, but found " + ch + "(" + ((int) ch) + + ")", reader.getMark()); + } + String value = reader.prefix(length); + reader.forward(length); + ch = reader.peek(); + if (NULL_BL_LINEBR.indexOf(ch) == -1) { + throw new ScannerException("while scanning a directive", startMark, + "expected alphabetic or numeric character, but found " + ch + "(" + ((int) ch) + + ")", reader.getMark()); + } + return value; + } + + private List<Integer> scanYamlDirectiveValue(Mark startMark) { + // See the specification for details. + while (reader.peek() == ' ') { + reader.forward(); + } + Integer major = scanYamlDirectiveNumber(startMark); + if (reader.peek() != '.') { + throw new ScannerException("while scanning a directive", startMark, + "expected a digit or '.', but found " + reader.peek() + "(" + + ((int) reader.peek()) + ")", reader.getMark()); + } + reader.forward(); + Integer minor = scanYamlDirectiveNumber(startMark); + if (NULL_BL_LINEBR.indexOf(reader.peek()) == -1) { + throw new ScannerException("while scanning a directive", startMark, + "expected a digit or ' ', but found " + reader.peek() + "(" + + ((int) reader.peek()) + ")", reader.getMark()); + } + List<Integer> result = new ArrayList<Integer>(2); + result.add(major); + result.add(minor); + return result; + } + + private Integer scanYamlDirectiveNumber(Mark startMark) { + // See the specification for details. + char ch = reader.peek(); + if (!Character.isDigit(ch)) { + throw new ScannerException("while scanning a directive", startMark, + "expected a digit, but found " + ch + "(" + ((int) ch) + ")", reader.getMark()); + } + int length = 0; + while (Character.isDigit(reader.peek(length))) { + length++; + } + Integer value = new Integer(reader.prefix(length)); + reader.forward(length); + return value; + } + + private List<String> scanTagDirectiveValue(Mark startMark) { + // See the specification for details. + while (reader.peek() == ' ') { + reader.forward(); + } + String handle = scanTagDirectiveHandle(startMark); + while (reader.peek() == ' ') { + reader.forward(); + } + String prefix = scanTagDirectivePrefix(startMark); + List<String> result = new ArrayList<String>(2); + result.add(handle); + result.add(prefix); + return result; + } + + private String scanTagDirectiveHandle(Mark startMark) { + // See the specification for details. + String value = scanTagHandle("directive", startMark); + char ch = reader.peek(); + if (ch != ' ') { + throw new ScannerException("while scanning a directive", startMark, + "expected ' ', but found " + reader.peek() + "(" + ch + ")", reader.getMark()); + } + return value; + } + + private String scanTagDirectivePrefix(Mark startMark) { + // See the specification for details. + String value = scanTagUri("directive", startMark); + if (NULL_BL_LINEBR.indexOf(reader.peek()) == -1) { + throw new ScannerException("while scanning a directive", startMark, + "expected ' ', but found " + reader.peek() + "(" + ((int) reader.peek()) + ")", + reader.getMark()); + } + return value; + } + + private String scanDirectiveIgnoredLine(Mark startMark) { + // See the specification for details. + while (reader.peek() == ' ') { + reader.forward(); + } + if (reader.peek() == '#') { + while (NULL_OR_LINEBR.indexOf(reader.peek()) == -1) { + reader.forward(); + } + } + char ch = reader.peek(); + if (NULL_OR_LINEBR.indexOf(ch) == -1) { + throw new ScannerException("while scanning a directive", startMark, + "expected a comment or a line break, but found " + ch + "(" + ((int) ch) + ")", + reader.getMark()); + } + return scanLineBreak(); + } + + /** + * <pre> + * The specification does not restrict characters for anchors and + * aliases. This may lead to problems, for instance, the document: + * [ *alias, value ] + * can be interpteted in two ways, as + * [ "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 (ALPHA.indexOf(ch) != -1) { + length++; + ch = reader.peek(length); + } + if (length == 0) { + throw new ScannerException("while scanning an " + name, startMark, + "expected alphabetic or numeric character, but found but found " + ch, reader + .getMark()); + } + String value = reader.prefix(length); + reader.forward(length); + ch = reader.peek(); + if ("\0 \t\r\n\u0085\u2028\u2029?:,]}%@`".indexOf(ch) == -1) { + throw new ScannerException("while scanning an " + name, startMark, + "expected alphabetic or numeric character, but found " + ch + "(" + + ((int) reader.peek()) + ")", reader.getMark()); + } + Mark endMark = reader.getMark(); + Token tok; + if (isAnchor) { + tok = new AnchorToken(value, startMark, endMark); + } else { + tok = new AliasToken(value, startMark, endMark); + } + return tok; + } + + private Token scanTag() { + // See the specification for details. + Mark startMark = reader.getMark(); + char ch = reader.peek(1); + String handle = null; + String suffix = null; + if (ch == '<') { + reader.forward(2); + suffix = scanTagUri("tag", startMark); + if (reader.peek() != '>') { + throw new ScannerException("while scanning a tag", startMark, + "expected '>', but found " + reader.peek() + "(" + ((int) reader.peek()) + + ")", reader.getMark()); + } + reader.forward(); + } else if (NULL_BL_T_LINEBR.indexOf(ch) != -1) { + suffix = "!"; + reader.forward(); + } else { + int length = 1; + boolean useHandle = false; + while ("\0 \r\n\u0085\u2028\u2029".indexOf(ch) == -1) { + if (ch == '!') { + useHandle = true; + break; + } + length++; + ch = reader.peek(length); + } + handle = "!"; + if (useHandle) { + handle = scanTagHandle("tag", startMark); + } else { + handle = "!"; + reader.forward(); + } + suffix = scanTagUri("tag", startMark); + } + ch = reader.peek(); + if (NULL_BL_LINEBR.indexOf(ch) == -1) { + throw new ScannerException("while scanning a tag", startMark, + "expected ' ', but found " + ch + "(" + ((int) ch) + ")", reader.getMark()); + } + String[] value = new String[] { handle, suffix }; + Mark endMark = reader.getMark(); + return new TagToken(value, startMark, endMark); + } + + private Token scanBlockScalar(char style) { + // See the specification for details. + boolean folded; + if (style == '>') { + folded = true; + } else { + folded = false; + } + StringBuffer chunks = new StringBuffer(); + Mark startMark = reader.getMark(); + // Scan the header. + reader.forward(); + Object[] chompi = scanBlockScalarIndicators(startMark); + Boolean chomping = (Boolean) chompi[0]; + int increment = ((Integer) chompi[1]).intValue(); + scanBlockScalarIgnoredLine(startMark); + + // Determine the indentation level and go to the first non-empty line. + int minIndent = this.indent + 1; + if (minIndent < 1) { + minIndent = 1; + } + String breaks = null; + int maxIndent = 0; + int indent = 0; + Mark endMark; + if (increment == -1) { + Object[] brme = scanBlockScalarIndentation(); + breaks = (String) brme[0]; + maxIndent = ((Integer) brme[1]).intValue(); + endMark = (Mark) brme[2]; + indent = Math.max(minIndent, maxIndent); + } else { + indent = minIndent + increment - 1; + Object[] brme = scanBlockScalarBreaks(indent); + breaks = (String) brme[0]; + endMark = (Mark) brme[1]; + } + + String lineBreak = ""; + + // Scan the inner part of the block scalar. + while (this.reader.getColumn() == indent && reader.peek() != '\0') { + chunks.append(breaks); + boolean leadingNonSpace = " \t".indexOf(reader.peek()) == -1; + int length = 0; + while (NULL_OR_LINEBR.indexOf(reader.peek(length)) == -1) { + length++; + } + chunks.append(reader.prefix(length)); + reader.forward(length); + lineBreak = scanLineBreak(); + Object[] brme = scanBlockScalarBreaks(indent); + breaks = (String) brme[0]; + endMark = (Mark) brme[1]; + if (this.reader.getColumn() == indent && reader.peek() != '\0') { + + // Unfortunately, folding rules are ambiguous. + // + // This is the folding according to the specification: + if (folded && lineBreak.equals("\n") && leadingNonSpace + && " \t".indexOf(reader.peek()) == -1) { + if (breaks.length() == 0) { + chunks.append(" "); + } + } else { + chunks.append(lineBreak); + } + // Clark Evans's interpretation (also in the spec examples) not + // imported from PyYAML + } else { + break; + } + } + // Chomp the tail. + if (chomping == null || chomping.booleanValue()) { + chunks.append(lineBreak); + } + if (chomping != null && chomping.booleanValue()) { + chunks.append(breaks); + } + // We are done. + return new ScalarToken(chunks.toString(), false, startMark, endMark, style); + } + + private Object[] scanBlockScalarIndicators(Mark startMark) { + // See the specification for details. + Boolean chomping = null; + int increment = -1; + char ch = reader.peek(); + if (ch == '-' || ch == '+') { + if (ch == '+') { + chomping = Boolean.TRUE; + } else { + chomping = Boolean.FALSE; + } + reader.forward(); + ch = reader.peek(); + if (Character.isDigit(ch)) { + increment = Integer.parseInt(String.valueOf(ch)); + if (increment == 0) { + throw new ScannerException("while scanning a block scalar", startMark, + "expected indentation indicator in the range 1-9, but found 0", reader + .getMark()); + } + reader.forward(); + } + } else if (Character.isDigit(ch)) { + increment = Integer.parseInt(String.valueOf(ch)); + if (increment == 0) { + throw new ScannerException("while scanning a block scalar", startMark, + "expected indentation indicator in the range 1-9, but found 0", reader + .getMark()); + } + reader.forward(); + ch = reader.peek(); + if (ch == '-' || ch == '+') { + if (ch == '+') { + chomping = Boolean.TRUE; + } else { + chomping = Boolean.FALSE; + } + reader.forward(); + } + } + ch = reader.peek(); + if (NULL_BL_LINEBR.indexOf(ch) == -1) { + throw new ScannerException("while scanning a block scalar", startMark, + "expected chomping or indentation indicators, but found " + ch, reader + .getMark()); + } + return new Object[] { chomping, new Integer(increment) }; + } + + private String scanBlockScalarIgnoredLine(Mark startMark) { + // See the specification for details. + while (reader.peek() == ' ') { + reader.forward(); + } + if (reader.peek() == '#') { + while (NULL_OR_LINEBR.indexOf(reader.peek()) == -1) { + reader.forward(); + } + } + char ch = reader.peek(); + if (NULL_OR_LINEBR.indexOf(ch) == -1) { + throw new ScannerException("while scanning a block scalar", startMark, + "expected a comment or a line break, but found " + ch, reader.getMark()); + } + return scanLineBreak(); + } + + private Object[] scanBlockScalarIndentation() { + // See the specification for details. + StringBuffer chunks = new StringBuffer(); + int maxIndent = 0; + Mark endMark = reader.getMark(); + while (" \r\n\u0085\u2028\u2029".indexOf(reader.peek()) != -1) { + if (reader.peek() != ' ') { + chunks.append(scanLineBreak()); + endMark = reader.getMark(); + } else { + reader.forward(); + if (this.reader.getColumn() > maxIndent) { + maxIndent = reader.getColumn(); + } + } + } + return new Object[] { chunks.toString(), new Integer(maxIndent), endMark }; + } + + private Object[] scanBlockScalarBreaks(int indent) { + // See the specification for details. + StringBuffer chunks = new StringBuffer(); + Mark endMark = reader.getMark(); + while (this.reader.getColumn() < indent && reader.peek() == ' ') { + reader.forward(); + } + while (FULL_LINEBR.indexOf(reader.peek()) != -1) { + chunks.append(scanLineBreak()); + endMark = reader.getMark(); + while (this.reader.getColumn() < indent && reader.peek() == ' ') { + reader.forward(); + } + } + return new Object[] { chunks.toString(), endMark }; + } + + /** + * <pre> + * See the specification for details. + * Note that we loose indentation rules for quoted scalars. Quoted + * scalars don't need to adhere indentation because " and ' clearly + * mark the beginning and the end of them. Therefore we are less + * restrictive then the specification requires. We only need to check + * that document separators are not included in scalars. + * </pre> + */ + private Token scanFlowScalar(char style) { + boolean _double; + if (style == '"') { + _double = true; + } else { + _double = false; + } + StringBuffer chunks = new StringBuffer(); + Mark startMark = reader.getMark(); + char quote = reader.peek(); + reader.forward(); + chunks.append(scanFlowScalarNonSpaces(_double, startMark)); + while (reader.peek() != quote) { + chunks.append(scanFlowScalarSpaces(startMark)); + chunks.append(scanFlowScalarNonSpaces(_double, startMark)); + } + reader.forward(); + Mark endMark = reader.getMark(); + return new ScalarToken(chunks.toString(), false, startMark, endMark, style); + } + + private String scanFlowScalarNonSpaces(boolean _double, Mark startMark) { + // See the specification for details. + StringBuffer chunks = new StringBuffer(); + while (true) { + int length = 0; + while ("\'\"\\\0 \t\r\n\u0085\u2028\u2029".indexOf(reader.peek(length)) == -1) { + length++; + } + if (length != 0) { + chunks.append(reader.prefix(length)); + reader.forward(length); + } + char ch = reader.peek(); + if (!_double && ch == '\'' && reader.peek(1) == '\'') { + chunks.append("'"); + reader.forward(2); + } else if ((_double && ch == '\'') || (!_double && "\"\\".indexOf(ch) != -1)) { + chunks.append(ch); + reader.forward(); + } else if (_double && ch == '\\') { + reader.forward(); + ch = reader.peek(); + if (ESCAPE_REPLACEMENTS.containsKey(new Character(ch))) { + chunks.append(ESCAPE_REPLACEMENTS.get(new Character(ch))); + reader.forward(); + } else if (ESCAPE_CODES.containsKey(new Character(ch))) { + length = ((Integer) ESCAPE_CODES.get(new Character(ch))).intValue(); + reader.forward(); + String val = reader.prefix(length); + if (NOT_HEXA.matcher(val).find()) { + throw new ScannerException("while scanning a double-quoted scalar", + startMark, "expected escape sequence of " + length + + " hexadecimal numbers, but found: " + val, reader + .getMark()); + } + char unicode = (char) Integer.parseInt(val, 16); + chunks.append(unicode); + reader.forward(length); + } else if (FULL_LINEBR.indexOf(ch) != -1) { + scanLineBreak(); + chunks.append(scanFlowScalarBreaks(startMark)); + } else { + throw new ScannerException("while scanning a double-quoted scalar", startMark, + "found unknown escape character " + ch + "(" + ((int) ch) + ")", reader + .getMark()); + } + } else { + return chunks.toString(); + } + } + } + + private String scanFlowScalarSpaces(Mark startMark) { + // See the specification for details. + StringBuffer chunks = new StringBuffer(); + int length = 0; + while (" \t".indexOf(reader.peek(length)) != -1) { + length++; + } + String whitespaces = reader.prefix(length); + reader.forward(length); + char ch = reader.peek(); + if (ch == '\0') { + throw new ScannerException("while scanning a quoted scalar", startMark, + "found unexpected end of stream", reader.getMark()); + } else if (FULL_LINEBR.indexOf(ch) != -1) { + String lineBreak = scanLineBreak(); + String breaks = scanFlowScalarBreaks(startMark); + if (!lineBreak.equals("\n")) { + chunks.append(lineBreak); + } else if (breaks.length() == 0) { + chunks.append(" "); + } + chunks.append(breaks); + } else { + chunks.append(whitespaces); + } + return chunks.toString(); + } + + private String scanFlowScalarBreaks(Mark startMark) { + // See the specification for details. + StringBuffer chunks = new StringBuffer(); + while (true) { + // Instead of checking indentation, we check for document + // separators. + String prefix = reader.prefix(3); + if ((prefix.equals("---") || prefix.equals("...")) + && NULL_BL_T_LINEBR.indexOf(reader.peek(3)) != -1) { + throw new ScannerException("while scanning a quoted scalar", startMark, + "found unexpected document separator", reader.getMark()); + } + while (" \t".indexOf(reader.peek()) != -1) { + reader.forward(); + } + if (FULL_LINEBR.indexOf(reader.peek()) != -1) { + chunks.append(scanLineBreak()); + } else { + return chunks.toString(); + } + } + } + + /** + * <pre> + * See the specification for details. + * We add an additional restriction for the flow context: + * plain scalars in the flow context cannot contain ',', ':' and '?'. + * We also keep track of the `allow_simple_key` flag here. + * Indentation rules are loosed for the flow context. + * </pre> + */ + private Token scanPlain() { + StringBuffer chunks = new StringBuffer(); + Mark startMark = reader.getMark(); + Mark endMark = startMark; + int indent = this.indent + 1; + String spaces = ""; + while (true) { + char ch; + int length = 0; + if (reader.peek() == '#') { + break; + } + while (true) { + ch = reader.peek(length); + if ("\0 \t\r\n\u0085\u2028\u2029".indexOf(ch) != -1 + || (this.flowLevel == 0 && ch == ':' && "\0 \t\r\n\u0085\u2028\u2029" + .indexOf(reader.peek(length + 1)) != -1) + || (this.flowLevel != 0 && ",:?[]{}".indexOf(ch) != -1)) { + break; + } + length++; + } + // It's not clear what we should do with ':' in the flow context. + if (this.flowLevel != 0 && ch == ':' + && "\0 \t\r\n\u0085\u2028\u2029,[]{}".indexOf(reader.peek(length + 1)) == -1) { + reader.forward(length); + throw new ScannerException("while scanning a plain scalar", startMark, + "found unexpected ':'", reader.getMark(), + "Please check http://pyyaml.org/wiki/YAMLColonInFlowContext for details."); + } + if (length == 0) { + break; + } + this.allowSimpleKey = false; + chunks.append(spaces); + chunks.append(reader.prefix(length)); + reader.forward(length); + endMark = reader.getMark(); + spaces = scanPlainSpaces(); + if ("".equals(spaces) || reader.peek() == '#' + || (this.flowLevel == 0 && this.reader.getColumn() < indent)) { + break; + } + } + return new ScalarToken(chunks.toString(), startMark, endMark, true); + } + + /** + * <pre> + * See the specification for details. + * The specification is really confusing about tabs in plain scalars. + * We just forbid them completely. Do not use tabs in YAML! + * </pre> + */ + private String scanPlainSpaces() { + StringBuffer chunks = new StringBuffer(); + int length = 0; + while (reader.peek(length) == ' ') { + length++; + } + String whitespaces = reader.prefix(length); + reader.forward(length); + char ch = reader.peek(); + if (FULL_LINEBR.indexOf(ch) != -1) { + String lineBreak = scanLineBreak(); + this.allowSimpleKey = true; + String prefix = reader.prefix(3); + if ("---".equals(prefix) || "...".equals(prefix) + && NULL_BL_T_LINEBR.indexOf(reader.peek(3)) != -1) { + return ""; + } + StringBuffer breaks = new StringBuffer(); + while (" \r\n\u0085\u2028\u2029".indexOf(reader.peek()) != -1) { + if (reader.peek() == ' ') { + reader.forward(); + } else { + breaks.append(scanLineBreak()); + prefix = reader.prefix(3); + if ("---".equals(prefix) || "...".equals(prefix) + && NULL_BL_T_LINEBR.indexOf(reader.peek(3)) != -1) { + return ""; + } + } + } + if (!lineBreak.equals("\n")) { + chunks.append(lineBreak); + } else if (breaks == null || breaks.toString().equals("")) { + chunks.append(" "); + } + chunks.append(breaks); + } else { + chunks.append(whitespaces); + } + return chunks.toString(); + } + + /** + * <pre> + * See the specification for details. + * For some strange reasons, the specification does not allow '_' in + * tag handles. I have allowed it anyway. + * </pre> + */ + private String scanTagHandle(String name, Mark startMark) { + char ch = reader.peek(); + if (ch != '!') { + throw new ScannerException("while scanning a " + name, startMark, + "expected '!', but found " + ch + "(" + ((int) ch) + ")", reader.getMark()); + } + int length = 1; + ch = reader.peek(length); + if (ch != ' ') { + while (ALPHA.indexOf(ch) != -1) { + length++; + ch = reader.peek(length); + } + if (ch != '!') { + reader.forward(length); + throw new ScannerException("while scanning a " + name, startMark, + "expected '!', but found " + ch + "(" + ((int) ch) + ")", reader.getMark()); + } + length++; + } + String value = reader.prefix(length); + reader.forward(length); + return value; + } + + private String scanTagUri(String name, Mark startMark) { + // See the specification for details. + // Note: we do not check if URI is well-formed. + StringBuffer chunks = new StringBuffer(); + int length = 0; + char ch = reader.peek(length); + while (ALPHA.indexOf(ch) != -1 || "-;/?:@&=+$,_.!~*\'()[]%".indexOf(ch) != -1) { + if (ch == '%') { + chunks.append(reader.prefix(length)); + reader.forward(length); + length = 0; + chunks.append(scanUriEscapes(name, startMark)); + } else { + length++; + } + ch = reader.peek(length); + } + if (length != 0) { + chunks.append(reader.prefix(length)); + reader.forward(length); + length = 0; + } + if (chunks.length() == 0) { + throw new ScannerException("while scanning a " + name, startMark, + "expected URI, but found " + ch + "(" + ((int) ch) + ")", reader.getMark()); + } + return chunks.toString(); + } + + private String scanUriEscapes(String name, Mark startMark) { + // See the specification for details. + StringBuffer bytes = new StringBuffer(); + while (reader.peek() == '%') { + reader.forward(); + try { + bytes.append(Integer.parseInt(reader.prefix(2), 16)); + } catch (NumberFormatException nfe) { + throw new ScannerException("while scanning a " + name, startMark, + "expected URI escape sequence of 2 hexadecimal numbers, but found " + + reader.peek(1) + "(" + ((int) reader.peek(1)) + ") and " + + reader.peek(2) + "(" + ((int) reader.peek(2)) + ")", reader + .getMark()); + } + reader.forward(2); + } + return bytes.toString(); + } + + private String scanLineBreak() { + // Transforms: + // '\r\n' : '\n' + // '\r' : '\n' + // '\n' : '\n' + // '\x85' : '\n' + // default : '' + char ch = reader.peek(); + if ("\r\n\u0085".indexOf(ch) != -1) { + if ("\r\n".equals(reader.prefix(2))) { + reader.forward(2); + } else { + reader.forward(); + } + return "\n"; + } else if ("\u2028\u2029".indexOf(ch) != -1) { + reader.forward(); + return String.valueOf(ch); + } + return ""; + } +} diff --git a/src/main/java/org/yaml/snakeyaml/scanner/SimpleKey.java b/src/main/java/org/yaml/snakeyaml/scanner/SimpleKey.java new file mode 100644 index 00000000..9d49e679 --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/scanner/SimpleKey.java @@ -0,0 +1,59 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.scanner; + +import org.yaml.snakeyaml.error.Mark; + +/** + * Simple keys treatment. + * + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +final class SimpleKey { + private int tokenNumber; + private boolean required; + private int index; + private int line; + private int column; + private Mark mark; + + public SimpleKey(int tokenNumber, boolean required, int index, int line, int column, Mark mark) { + this.tokenNumber = tokenNumber; + this.required = required; + this.index = index; + this.line = line; + this.column = column; + this.mark = mark; + } + + public int getTokenNumber() { + return this.tokenNumber; + } + + public int getColumn() { + return this.column; + } + + public Mark getMark() { + return mark; + } + + public int getIndex() { + return index; + } + + public int getLine() { + return line; + } + + public boolean isRequired() { + return required; + } + + @Override + public String toString() { + return "SimpleKey - tokenNumber=" + tokenNumber + " required=" + required + " index=" + + index + " line=" + line + " column=" + column; + } +} diff --git a/src/main/java/org/yaml/snakeyaml/serializer/Serializer.java b/src/main/java/org/yaml/snakeyaml/serializer/Serializer.java new file mode 100644 index 00000000..0468d007 --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/serializer/Serializer.java @@ -0,0 +1,191 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.serializer; + +import java.io.IOException; +import java.text.NumberFormat; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.yaml.snakeyaml.DumperOptions; +import org.yaml.snakeyaml.emitter.Emitter; +import org.yaml.snakeyaml.events.AliasEvent; +import org.yaml.snakeyaml.events.DocumentEndEvent; +import org.yaml.snakeyaml.events.DocumentStartEvent; +import org.yaml.snakeyaml.events.MappingEndEvent; +import org.yaml.snakeyaml.events.MappingStartEvent; +import org.yaml.snakeyaml.events.ScalarEvent; +import org.yaml.snakeyaml.events.SequenceEndEvent; +import org.yaml.snakeyaml.events.SequenceStartEvent; +import org.yaml.snakeyaml.events.StreamEndEvent; +import org.yaml.snakeyaml.events.StreamStartEvent; +import org.yaml.snakeyaml.nodes.CollectionNode; +import org.yaml.snakeyaml.nodes.Node; +import org.yaml.snakeyaml.nodes.NodeId; +import org.yaml.snakeyaml.nodes.ScalarNode; +import org.yaml.snakeyaml.resolver.Resolver; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public final class Serializer { + private final Emitter emitter; + private final Resolver resolver; + private boolean explicitStart; + private boolean explicitEnd; + private Integer[] useVersion; + private Map<String, String> useTags; + private Set<Node> serializedNodes; + private Map<Node, String> anchors; + private int lastAnchorId; + private Boolean closed; + private String explicitRoot; + + public Serializer(Emitter emitter, Resolver resolver, DumperOptions opts) { + this.emitter = emitter; + this.resolver = resolver; + this.explicitStart = opts.isExplicitStart(); + this.explicitEnd = opts.isExplicitEnd(); + if (opts.getVersion() != null) { + this.useVersion = opts.getVersion().getArray(); + } + this.useTags = opts.getTags(); + this.serializedNodes = new HashSet<Node>(); + this.anchors = new HashMap<Node, String>(); + this.lastAnchorId = 0; + this.closed = null; + this.explicitRoot = opts.getExplicitRoot(); + } + + public void open() throws IOException { + if (closed == null) { + this.emitter.emit(new StreamStartEvent(null, null)); + this.closed = Boolean.FALSE; + } else if (Boolean.TRUE.equals(closed)) { + throw new SerializerException("serializer is closed"); + } else { + throw new SerializerException("serializer is already opened"); + } + } + + public void close() throws IOException { + if (closed == null) { + throw new SerializerException("serializer is not opened"); + } else if (!Boolean.TRUE.equals(closed)) { + this.emitter.emit(new StreamEndEvent(null, null)); + this.closed = Boolean.TRUE; + } + } + + public void serialize(Node node) throws IOException { + if (closed == null) { + throw new SerializerException("serializer is not opened"); + } else if (closed) { + throw new SerializerException("serializer is closed"); + } + this.emitter.emit(new DocumentStartEvent(null, null, this.explicitStart, this.useVersion, + useTags)); + anchorNode(node); + if (explicitRoot != null) { + node.setTag(explicitRoot); + } + serializeNode(node, null, null); + this.emitter.emit(new DocumentEndEvent(null, null, this.explicitEnd)); + this.serializedNodes.clear(); + this.anchors.clear(); + this.lastAnchorId = 0; + } + + @SuppressWarnings("unchecked") + private void anchorNode(Node node) { + if (this.anchors.containsKey(node)) { + String anchor = this.anchors.get(node); + if (null == anchor) { + anchor = generateAnchor(); + this.anchors.put(node, anchor); + } + } else { + this.anchors.put(node, null); + switch (node.getNodeId()) { + case sequence: + List<Node> list = (List<Node>) node.getValue(); + for (Node item : list) { + anchorNode(item); + } + break; + case mapping: + List<Object[]> map = (List<Object[]>) node.getValue(); + for (Object[] object : map) { + Node key = (Node) object[0]; + Node value = (Node) object[1]; + anchorNode(key); + anchorNode(value); + } + break; + } + } + } + + private String generateAnchor() { + this.lastAnchorId++; + NumberFormat format = NumberFormat.getNumberInstance(); + format.setMinimumIntegerDigits(3); + String anchorId = format.format(this.lastAnchorId); + return "id" + anchorId; + } + + @SuppressWarnings("unchecked") + private void serializeNode(Node node, Node parent, Object index) throws IOException { + String tAlias = this.anchors.get(node); + if (this.serializedNodes.contains(node)) { + this.emitter.emit(new AliasEvent(tAlias, null, null)); + } else { + this.serializedNodes.add(node); + // this.resolver.descendResolver(parent, index); + switch (node.getNodeId()) { + case scalar: + String detectedTag = this.resolver.resolve(NodeId.scalar, (String) node.getValue(), + true); + String defaultTag = this.resolver.resolve(NodeId.scalar, (String) node.getValue(), + false); + boolean[] implicit = new boolean[] { false, false }; + implicit[0] = node.getTag().equals(detectedTag); + implicit[1] = node.getTag().equals(defaultTag); + ScalarEvent event = new ScalarEvent(tAlias, node.getTag(), implicit, (String) node + .getValue(), null, null, ((ScalarNode) node).getStyle()); + this.emitter.emit(event); + break; + case sequence: + boolean implicitS = (node.getTag().equals(this.resolver.resolve(NodeId.sequence, + null, true))); + this.emitter.emit(new SequenceStartEvent(tAlias, node.getTag(), implicitS, null, + null, ((CollectionNode) node).getFlowStyle())); + int indexCounter = 0; + List<Node> list = (List<Node>) node.getValue(); + for (Node item : list) { + serializeNode(item, node, new Integer(indexCounter)); + indexCounter++; + } + this.emitter.emit(new SequenceEndEvent(null, null)); + break; + default:// instance of MappingNode + String implicitTag = this.resolver.resolve(NodeId.mapping, null, true); + boolean implicitM = (node.getTag().equals(implicitTag)); + this.emitter.emit(new MappingStartEvent(tAlias, node.getTag(), implicitM, null, + null, ((CollectionNode) node).getFlowStyle())); + List<Object[]> map = (List<Object[]>) node.getValue(); + for (Object[] row : map) { + Node key = (Node) row[0]; + Node value = (Node) row[1]; + serializeNode(key, node, null); + serializeNode(value, node, key); + } + this.emitter.emit(new MappingEndEvent(null, null)); + } + } + } +} diff --git a/src/main/java/org/yaml/snakeyaml/serializer/SerializerException.java b/src/main/java/org/yaml/snakeyaml/serializer/SerializerException.java new file mode 100644 index 00000000..202abcf4 --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/serializer/SerializerException.java @@ -0,0 +1,17 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.serializer; + +import org.yaml.snakeyaml.error.YAMLException; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public class SerializerException extends YAMLException { + private static final long serialVersionUID = 2632638197498912433L; + + public SerializerException(String message) { + super(message); + } +} diff --git a/src/main/java/org/yaml/snakeyaml/tokens/AliasToken.java b/src/main/java/org/yaml/snakeyaml/tokens/AliasToken.java new file mode 100644 index 00000000..aa0eba8b --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/tokens/AliasToken.java @@ -0,0 +1,32 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.tokens; + +import org.yaml.snakeyaml.error.Mark; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public final class AliasToken extends Token { + private final String value; + + public AliasToken(String value, Mark startMark, Mark endMark) { + super(startMark, endMark); + this.value = value; + } + + public String getValue() { + return this.value; + } + + @Override + protected String getArguments() { + return "value=" + value; + } + + @Override + public String getTokenId() { + return "<alias>"; + } +} diff --git a/src/main/java/org/yaml/snakeyaml/tokens/AnchorToken.java b/src/main/java/org/yaml/snakeyaml/tokens/AnchorToken.java new file mode 100644 index 00000000..c58a967c --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/tokens/AnchorToken.java @@ -0,0 +1,32 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.tokens; + +import org.yaml.snakeyaml.error.Mark; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public final class AnchorToken extends Token { + private final String value; + + public AnchorToken(String value, Mark startMark, Mark endMark) { + super(startMark, endMark); + this.value = value; + } + + public String getValue() { + return this.value; + } + + @Override + protected String getArguments() { + return "value=" + value; + } + + @Override + public String getTokenId() { + return "<anchor>"; + } +} diff --git a/src/main/java/org/yaml/snakeyaml/tokens/BlockEndToken.java b/src/main/java/org/yaml/snakeyaml/tokens/BlockEndToken.java new file mode 100644 index 00000000..8dbe15fc --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/tokens/BlockEndToken.java @@ -0,0 +1,21 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.tokens; + +import org.yaml.snakeyaml.error.Mark; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public final class BlockEndToken extends Token { + + public BlockEndToken(Mark startMark, Mark endMark) { + super(startMark, endMark); + } + + @Override + public String getTokenId() { + return "<block end>"; + } +} diff --git a/src/main/java/org/yaml/snakeyaml/tokens/BlockEntryToken.java b/src/main/java/org/yaml/snakeyaml/tokens/BlockEntryToken.java new file mode 100644 index 00000000..d0ba8f0d --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/tokens/BlockEntryToken.java @@ -0,0 +1,21 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.tokens; + +import org.yaml.snakeyaml.error.Mark; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public final class BlockEntryToken extends Token { + + public BlockEntryToken(Mark startMark, Mark endMark) { + super(startMark, endMark); + } + + @Override + public String getTokenId() { + return "-"; + } +} diff --git a/src/main/java/org/yaml/snakeyaml/tokens/BlockMappingStartToken.java b/src/main/java/org/yaml/snakeyaml/tokens/BlockMappingStartToken.java new file mode 100644 index 00000000..04616a0c --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/tokens/BlockMappingStartToken.java @@ -0,0 +1,21 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.tokens; + +import org.yaml.snakeyaml.error.Mark; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public final class BlockMappingStartToken extends Token { + + public BlockMappingStartToken(Mark startMark, Mark endMark) { + super(startMark, endMark); + } + + @Override + public String getTokenId() { + return "<block mapping start>"; + } +} diff --git a/src/main/java/org/yaml/snakeyaml/tokens/BlockSequenceStartToken.java b/src/main/java/org/yaml/snakeyaml/tokens/BlockSequenceStartToken.java new file mode 100644 index 00000000..5df7080a --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/tokens/BlockSequenceStartToken.java @@ -0,0 +1,21 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.tokens; + +import org.yaml.snakeyaml.error.Mark; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public final class BlockSequenceStartToken extends Token { + + public BlockSequenceStartToken(Mark startMark, Mark endMark) { + super(startMark, endMark); + } + + @Override + public String getTokenId() { + return "<block sequence start>"; + } +} diff --git a/src/main/java/org/yaml/snakeyaml/tokens/DirectiveToken.java b/src/main/java/org/yaml/snakeyaml/tokens/DirectiveToken.java new file mode 100644 index 00000000..f016ed95 --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/tokens/DirectiveToken.java @@ -0,0 +1,49 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.tokens; + +import java.util.List; + +import org.yaml.snakeyaml.error.Mark; +import org.yaml.snakeyaml.error.YAMLException; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public final class DirectiveToken extends Token { + private final String name; + private final List<?> value; + + public DirectiveToken(String name, List<?> value, Mark startMark, Mark endMark) { + super(startMark, endMark); + this.name = name; + if (value != null && value.size() != 2) { + throw new YAMLException("Two strings must be provided instead of " + + String.valueOf(value.size())); + } + this.value = value; + } + + public String getName() { + return this.name; + } + + public List<?> getValue() { + return this.value; + } + + @Override + protected String getArguments() { + if (value != null) { + return "name=" + name + ", value=[" + value.get(0) + ", " + value.get(1) + "]"; + } else { + return "name=" + name; + } + } + + @Override + public String getTokenId() { + return "<directive>"; + } +} diff --git a/src/main/java/org/yaml/snakeyaml/tokens/DocumentEndToken.java b/src/main/java/org/yaml/snakeyaml/tokens/DocumentEndToken.java new file mode 100644 index 00000000..c74b9ced --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/tokens/DocumentEndToken.java @@ -0,0 +1,21 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.tokens; + +import org.yaml.snakeyaml.error.Mark; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public final class DocumentEndToken extends Token { + + public DocumentEndToken(Mark startMark, Mark endMark) { + super(startMark, endMark); + } + + @Override + public String getTokenId() { + return "<document end>"; + } +} diff --git a/src/main/java/org/yaml/snakeyaml/tokens/DocumentStartToken.java b/src/main/java/org/yaml/snakeyaml/tokens/DocumentStartToken.java new file mode 100644 index 00000000..845ac769 --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/tokens/DocumentStartToken.java @@ -0,0 +1,21 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.tokens; + +import org.yaml.snakeyaml.error.Mark; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public final class DocumentStartToken extends Token { + + public DocumentStartToken(Mark startMark, Mark endMark) { + super(startMark, endMark); + } + + @Override + public String getTokenId() { + return "<document start>"; + } +} diff --git a/src/main/java/org/yaml/snakeyaml/tokens/FlowEntryToken.java b/src/main/java/org/yaml/snakeyaml/tokens/FlowEntryToken.java new file mode 100644 index 00000000..620708cb --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/tokens/FlowEntryToken.java @@ -0,0 +1,21 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.tokens; + +import org.yaml.snakeyaml.error.Mark; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public final class FlowEntryToken extends Token { + + public FlowEntryToken(Mark startMark, Mark endMark) { + super(startMark, endMark); + } + + @Override + public String getTokenId() { + return ","; + } +} diff --git a/src/main/java/org/yaml/snakeyaml/tokens/FlowMappingEndToken.java b/src/main/java/org/yaml/snakeyaml/tokens/FlowMappingEndToken.java new file mode 100644 index 00000000..2da86fe6 --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/tokens/FlowMappingEndToken.java @@ -0,0 +1,21 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.tokens; + +import org.yaml.snakeyaml.error.Mark; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public final class FlowMappingEndToken extends Token { + + public FlowMappingEndToken(Mark startMark, Mark endMark) { + super(startMark, endMark); + } + + @Override + public String getTokenId() { + return "}"; + } +} diff --git a/src/main/java/org/yaml/snakeyaml/tokens/FlowMappingStartToken.java b/src/main/java/org/yaml/snakeyaml/tokens/FlowMappingStartToken.java new file mode 100644 index 00000000..fc553108 --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/tokens/FlowMappingStartToken.java @@ -0,0 +1,21 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.tokens; + +import org.yaml.snakeyaml.error.Mark; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public final class FlowMappingStartToken extends Token { + + public FlowMappingStartToken(Mark startMark, Mark endMark) { + super(startMark, endMark); + } + + @Override + public String getTokenId() { + return "{"; + } +} diff --git a/src/main/java/org/yaml/snakeyaml/tokens/FlowSequenceEndToken.java b/src/main/java/org/yaml/snakeyaml/tokens/FlowSequenceEndToken.java new file mode 100644 index 00000000..438eed81 --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/tokens/FlowSequenceEndToken.java @@ -0,0 +1,21 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.tokens; + +import org.yaml.snakeyaml.error.Mark; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public final class FlowSequenceEndToken extends Token { + + public FlowSequenceEndToken(Mark startMark, Mark endMark) { + super(startMark, endMark); + } + + @Override + public String getTokenId() { + return "]"; + } +} diff --git a/src/main/java/org/yaml/snakeyaml/tokens/FlowSequenceStartToken.java b/src/main/java/org/yaml/snakeyaml/tokens/FlowSequenceStartToken.java new file mode 100644 index 00000000..136e408d --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/tokens/FlowSequenceStartToken.java @@ -0,0 +1,21 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.tokens; + +import org.yaml.snakeyaml.error.Mark; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public final class FlowSequenceStartToken extends Token { + + public FlowSequenceStartToken(Mark startMark, Mark endMark) { + super(startMark, endMark); + } + + @Override + public String getTokenId() { + return "["; + } +} diff --git a/src/main/java/org/yaml/snakeyaml/tokens/KeyToken.java b/src/main/java/org/yaml/snakeyaml/tokens/KeyToken.java new file mode 100644 index 00000000..8d80512c --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/tokens/KeyToken.java @@ -0,0 +1,21 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.tokens; + +import org.yaml.snakeyaml.error.Mark; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public final class KeyToken extends Token { + + public KeyToken(Mark startMark, Mark endMark) { + super(startMark, endMark); + } + + @Override + public String getTokenId() { + return "?"; + } +} diff --git a/src/main/java/org/yaml/snakeyaml/tokens/ScalarToken.java b/src/main/java/org/yaml/snakeyaml/tokens/ScalarToken.java new file mode 100644 index 00000000..90a3cbbc --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/tokens/ScalarToken.java @@ -0,0 +1,48 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.tokens; + +import org.yaml.snakeyaml.error.Mark; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public final class ScalarToken extends Token { + private final String value; + private final boolean plain; + private final char style; + + public ScalarToken(String value, Mark startMark, Mark endMark, boolean plain) { + this(value, plain, startMark, endMark, (char) 0); + } + + public ScalarToken(String value, boolean plain, Mark startMark, Mark endMark, char style) { + super(startMark, endMark); + this.value = value; + this.plain = plain; + this.style = style; + } + + public boolean getPlain() { + return this.plain; + } + + public String getValue() { + return this.value; + } + + public char getStyle() { + return this.style; + } + + @Override + protected String getArguments() { + return "value=" + value + ", plain=" + plain + ", style=" + style; + } + + @Override + public String getTokenId() { + return "<scalar>"; + } +} diff --git a/src/main/java/org/yaml/snakeyaml/tokens/StreamEndToken.java b/src/main/java/org/yaml/snakeyaml/tokens/StreamEndToken.java new file mode 100644 index 00000000..b14fd50a --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/tokens/StreamEndToken.java @@ -0,0 +1,21 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.tokens; + +import org.yaml.snakeyaml.error.Mark; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public final class StreamEndToken extends Token { + + public StreamEndToken(Mark startMark, Mark endMark) { + super(startMark, endMark); + } + + @Override + public String getTokenId() { + return "<stream end>"; + } +} diff --git a/src/main/java/org/yaml/snakeyaml/tokens/StreamStartToken.java b/src/main/java/org/yaml/snakeyaml/tokens/StreamStartToken.java new file mode 100644 index 00000000..a6f26f7b --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/tokens/StreamStartToken.java @@ -0,0 +1,21 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.tokens; + +import org.yaml.snakeyaml.error.Mark; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public final class StreamStartToken extends Token { + + public StreamStartToken(Mark startMark, Mark endMark) { + super(startMark, endMark); + } + + @Override + public String getTokenId() { + return "<stream start>"; + } +} diff --git a/src/main/java/org/yaml/snakeyaml/tokens/TagToken.java b/src/main/java/org/yaml/snakeyaml/tokens/TagToken.java new file mode 100644 index 00000000..e56bc342 --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/tokens/TagToken.java @@ -0,0 +1,37 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.tokens; + +import org.yaml.snakeyaml.error.Mark; +import org.yaml.snakeyaml.error.YAMLException; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public final class TagToken extends Token { + private final String[] value; + + public TagToken(String[] value, Mark startMark, Mark endMark) { + super(startMark, endMark); + if (value.length != 2) { + throw new YAMLException("Two strings must be provided instead of " + + String.valueOf(value.length)); + } + this.value = value; + } + + public String[] getValue() { + return this.value; + } + + @Override + protected String getArguments() { + return "value=[" + value[0] + ", " + value[1] + "]"; + } + + @Override + public String getTokenId() { + return "<tag>"; + } +} diff --git a/src/main/java/org/yaml/snakeyaml/tokens/Token.java b/src/main/java/org/yaml/snakeyaml/tokens/Token.java new file mode 100644 index 00000000..0daadd2f --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/tokens/Token.java @@ -0,0 +1,59 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.tokens; + +import org.yaml.snakeyaml.error.Mark; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public abstract class Token { + private final Mark startMark; + private final Mark endMark; + + public Token(Mark startMark, Mark endMark) { + assert startMark != null; + assert endMark != null; + this.startMark = startMark; + this.endMark = endMark; + } + + public String toString() { + return "<" + this.getClass().getName() + "(" + getArguments() + ")>"; + } + + public Mark getStartMark() { + return startMark; + } + + public Mark getEndMark() { + return endMark; + } + + /** + * @see __repr__ for Token in PyYAML + */ + protected String getArguments() { + return ""; + } + + /** + * For error reporting. + * + * @see class variable 'id' in PyYAML + */ + public abstract String getTokenId(); + + /* + * for tests only + */ + @Override + public boolean equals(Object obj) { + if (obj instanceof Token) { + return toString().equals(obj.toString()); + } else { + return false; + } + } +} diff --git a/src/main/java/org/yaml/snakeyaml/tokens/ValueToken.java b/src/main/java/org/yaml/snakeyaml/tokens/ValueToken.java new file mode 100644 index 00000000..2042aee8 --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/tokens/ValueToken.java @@ -0,0 +1,21 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.tokens; + +import org.yaml.snakeyaml.error.Mark; + +/** + * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information + */ +public final class ValueToken extends Token { + + public ValueToken(Mark startMark, Mark endMark) { + super(startMark, endMark); + } + + @Override + public String getTokenId() { + return ":"; + } +} diff --git a/src/main/java/org/yaml/snakeyaml/util/Base64Coder.java b/src/main/java/org/yaml/snakeyaml/util/Base64Coder.java new file mode 100644 index 00000000..539c41c5 --- /dev/null +++ b/src/main/java/org/yaml/snakeyaml/util/Base64Coder.java @@ -0,0 +1,109 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.util;
+
+import org.yaml.snakeyaml.error.YAMLException;
+
+public abstract class Base64Coder {
+ // Mapping table from 6-bit nibbles to Base64 characters.
+ private final static char[] map1 = new char[64];
+ static {
+ int i = 0;
+ for (char c = 'A'; c <= 'Z'; c++)
+ map1[i++] = c;
+ for (char c = 'a'; c <= 'z'; c++)
+ map1[i++] = c;
+ for (char c = '0'; c <= '9'; c++)
+ map1[i++] = c;
+ map1[i++] = '+';
+ map1[i++] = '/';
+ }
+
+ // Mapping table from Base64 characters to 6-bit nibbles.
+ private final static byte[] map2 = new byte[128];
+ static {
+ for (int i = 0; i < map2.length; i++)
+ map2[i] = -1;
+ for (int i = 0; i < 64; i++)
+ map2[map1[i]] = (byte) i;
+ }
+
+ /**
+ * Encodes a byte array into Base64 format. No blanks or line breaks are
+ * inserted.
+ *
+ * @param in
+ * an array containing the data bytes to be encoded.
+ * @return A character array with the Base64 encoded data.
+ */
+ public static char[] encode(byte[] in) {
+ int iLen = in.length;
+ int oDataLen = (iLen * 4 + 2) / 3; // output length without padding
+ int oLen = ((iLen + 2) / 3) * 4; // output length including padding
+ char[] out = new char[oLen];
+ int ip = 0;
+ int op = 0;
+ while (ip < iLen) {
+ int i0 = in[ip++] & 0xff;
+ int i1 = ip < iLen ? in[ip++] & 0xff : 0;
+ int i2 = ip < iLen ? in[ip++] & 0xff : 0;
+ int o0 = i0 >>> 2;
+ int o1 = ((i0 & 3) << 4) | (i1 >>> 4);
+ int o2 = ((i1 & 0xf) << 2) | (i2 >>> 6);
+ int o3 = i2 & 0x3F;
+ out[op++] = map1[o0];
+ out[op++] = map1[o1];
+ out[op] = op < oDataLen ? map1[o2] : '=';
+ op++;
+ out[op] = op < oDataLen ? map1[o3] : '=';
+ op++;
+ }
+ return out;
+ }
+
+ /**
+ * Decodes Base64 data. No blanks or line breaks are allowed within the
+ * Base64 encoded data.
+ *
+ * @param in
+ * a character array containing the Base64 encoded data.
+ * @return An array containing the decoded data bytes.
+ * @throws IllegalArgumentException
+ * if the input is not valid Base64 encoded data.
+ */
+ public static byte[] decode(char[] in) {
+ int iLen = in.length;
+ if (iLen % 4 != 0)
+ throw new YAMLException("Length of Base64 encoded input string is not a multiple of 4.");
+ while (iLen > 0 && in[iLen - 1] == '=')
+ iLen--;
+ int oLen = (iLen * 3) / 4;
+ byte[] out = new byte[oLen];
+ int ip = 0;
+ int op = 0;
+ while (ip < iLen) {
+ int i0 = in[ip++];
+ int i1 = in[ip++];
+ int i2 = ip < iLen ? in[ip++] : 'A';
+ int i3 = ip < iLen ? in[ip++] : 'A';
+ if (i0 > 127 || i1 > 127 || i2 > 127 || i3 > 127)
+ throw new YAMLException("Illegal character in Base64 encoded data.");
+ int b0 = map2[i0];
+ int b1 = map2[i1];
+ int b2 = map2[i2];
+ int b3 = map2[i3];
+ if (b0 < 0 || b1 < 0 || b2 < 0 || b3 < 0)
+ throw new YAMLException("Illegal character in Base64 encoded data.");
+ int o0 = (b0 << 2) | (b1 >>> 4);
+ int o1 = ((b1 & 0xf) << 4) | (b2 >>> 2);
+ int o2 = ((b2 & 3) << 6) | b3;
+ out[op++] = (byte) o0;
+ if (op < oLen)
+ out[op++] = (byte) o1;
+ if (op < oLen)
+ out[op++] = (byte) o2;
+ }
+ return out;
+ }
+}
diff --git a/src/test/java/examples/AnyObjectExampleTest.java b/src/test/java/examples/AnyObjectExampleTest.java new file mode 100644 index 00000000..9a599d87 --- /dev/null +++ b/src/test/java/examples/AnyObjectExampleTest.java @@ -0,0 +1,50 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package examples;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+
+public class AnyObjectExampleTest extends TestCase {
+ @SuppressWarnings("unchecked")
+ public void testLoad() throws IOException {
+ String doc = Util.getLocalResource("examples/any-object-example.yaml");
+ System.out.println(doc);
+ Yaml yaml = new Yaml();
+ Map<String, Object> object = (Map<String, Object>) yaml.load(doc);
+ System.out.println(object);
+ assertEquals(6, object.size());
+ assertEquals("[null, null]", object.get("none").toString());
+ List list1 = (List) object.get("none");
+ assertEquals(2, list1.size());
+ for (Object object2 : list1) {
+ assertNull(object2);
+ }
+ //
+ assertEquals("[true, false, true, false]", object.get("bool").toString());
+ assertEquals(4, ((List) object.get("bool")).size());
+ //
+ assertEquals(new Integer(42), object.get("int"));
+ assertEquals(new Double(3.14159), object.get("float"));
+ //
+ assertEquals("[LITE, RES_ACID, SUS_DEXT]", object.get("list").toString());
+ List list2 = (List) object.get("list");
+ assertEquals(3, list2.size());
+ for (Object object2 : list2) {
+ assertEquals(object2.toString(), object2.toString().toUpperCase());
+ }
+ //
+ assertEquals("{hp=13, sp=5}", object.get("dict").toString());
+ Map<String, Integer> map = (Map<String, Integer>) object.get("dict");
+ assertEquals(2, map.keySet().size());
+ assertEquals(new Integer(13), map.get("hp"));
+ assertEquals(new Integer(5), map.get("sp"));
+ }
+}
diff --git a/src/test/java/examples/CollectionStyleTest.java b/src/test/java/examples/CollectionStyleTest.java new file mode 100644 index 00000000..4529f993 --- /dev/null +++ b/src/test/java/examples/CollectionStyleTest.java @@ -0,0 +1,28 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package examples;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Yaml;
+
+public class CollectionStyleTest extends TestCase {
+ public void testNestedStyle() {
+ Yaml yaml = new Yaml();
+ String document = " a: 1\n b:\n c: 3\n d: 4\n";
+ System.out.println(document);
+ System.out.println(yaml.dump(yaml.load(document)));
+ assertEquals("a: 1\nb: {c: 3, d: 4}\n", yaml.dump(yaml.load(document)));
+ }
+
+ public void testNestedStyle2() {
+ DumperOptions options = new DumperOptions();
+ options.setDefaultFlowStyle(DumperOptions.DefaultFlowStyle.BLOCK);
+ Yaml yaml = new Yaml(options);
+ String document = " a: 1\n b:\n c: 3\n d: 4\n";
+ System.out.println(yaml.dump(yaml.load(document)));
+ assertEquals("a: 1\nb:\n c: 3\n d: 4\n", yaml.dump(yaml.load(document)));
+ }
+}
diff --git a/src/test/java/examples/CustomConstructor.java b/src/test/java/examples/CustomConstructor.java new file mode 100644 index 00000000..a057fa27 --- /dev/null +++ b/src/test/java/examples/CustomConstructor.java @@ -0,0 +1,22 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package examples;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.yaml.snakeyaml.Invoice;
+import org.yaml.snakeyaml.constructor.Constructor;
+
+public class CustomConstructor extends Constructor {
+
+ public CustomConstructor() {
+ super(Invoice.class);
+ }
+
+ @Override
+ protected List<Object> createDefaultList(int initSize) {
+ return new ArrayList<Object>(initSize);
+ }
+}
\ No newline at end of file diff --git a/src/test/java/examples/CustomListExampleTest.java b/src/test/java/examples/CustomListExampleTest.java new file mode 100644 index 00000000..dc4fae51 --- /dev/null +++ b/src/test/java/examples/CustomListExampleTest.java @@ -0,0 +1,31 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package examples;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Loader;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.Constructor;
+
+public class CustomListExampleTest extends TestCase {
+ @SuppressWarnings("unchecked")
+ public void testList() throws IOException {
+ Loader loader = new Loader(new CustomConstructor());
+ Yaml yaml = new Yaml(loader);
+ List<Integer> data = (List<Integer>) yaml.load("[1, 2, 3]");
+ assertTrue(data instanceof ArrayList);
+ }
+
+ class CustomConstructor extends Constructor {
+ @Override
+ protected List<Object> createDefaultList(int initSize) {
+ return new ArrayList<Object>(initSize);
+ }
+ }
+}
diff --git a/src/test/java/examples/CustomMapExampleTest.java b/src/test/java/examples/CustomMapExampleTest.java new file mode 100644 index 00000000..624cdfab --- /dev/null +++ b/src/test/java/examples/CustomMapExampleTest.java @@ -0,0 +1,36 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package examples;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.TreeMap;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Loader;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.Constructor;
+
+public class CustomMapExampleTest extends TestCase {
+ @SuppressWarnings("unchecked")
+ public void testMap() throws IOException {
+ Loader loader = new Loader(new CustomConstructor());
+ Yaml yaml = new Yaml(loader);
+ Map data = (Map) yaml.load("{2: '222', 1: '111', 3: '333'}");
+ assertTrue(data instanceof TreeMap);
+ Object[] keys = data.keySet().toArray();
+ // must be sorted
+ assertEquals(new Integer(1), keys[0]);
+ assertEquals(new Integer(2), keys[1]);
+ assertEquals(new Integer(3), keys[2]);
+ }
+
+ class CustomConstructor extends Constructor {
+ @Override
+ protected Map<Object, Object> createDefaultMap() {
+ return new TreeMap<Object, Object>();
+ }
+ }
+}
diff --git a/src/test/java/examples/Dice.java b/src/test/java/examples/Dice.java new file mode 100644 index 00000000..25a24768 --- /dev/null +++ b/src/test/java/examples/Dice.java @@ -0,0 +1,41 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package examples;
+
+public class Dice {
+ private Integer a;
+ private Integer b;
+
+ public Dice(Integer a, Integer b) {
+ super();
+ this.a = a;
+ this.b = b;
+ }
+
+ public Integer getA() {
+ return a;
+ }
+
+ public Integer getB() {
+ return b;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof Dice) {
+ return toString().equals(obj.toString());
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return toString().hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return "Dice " + a + "d" + b;
+ }
+}
diff --git a/src/test/java/examples/DiceExampleTest.java b/src/test/java/examples/DiceExampleTest.java new file mode 100644 index 00000000..f0ff3728 --- /dev/null +++ b/src/test/java/examples/DiceExampleTest.java @@ -0,0 +1,97 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package examples;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Dumper;
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Loader;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.Construct;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.ScalarNode;
+import org.yaml.snakeyaml.representer.Represent;
+import org.yaml.snakeyaml.representer.Representer;
+
+public class DiceExampleTest extends TestCase {
+ public void testRepresenter() throws IOException {
+ Dice dice = new Dice(3, 6);
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(dice);
+ System.out.println(output);
+ assertEquals("!!examples.Dice {a: 3, b: 6}\n", output);
+ }
+
+ public void testDiceRepresenter() throws IOException {
+ Dice dice = new Dice(3, 6);
+ Map<String, Dice> data = new HashMap<String, Dice>();
+ data.put("gold", dice);
+ Yaml yaml = new Yaml(new Dumper(new DiceRepresenter(), new DumperOptions()));
+ String output = yaml.dump(data);
+ System.out.println(output);
+ assertEquals("{gold: !dice '3d6'}\n", output);
+ }
+
+ class DiceRepresenter extends Representer {
+ public DiceRepresenter() {
+ this.representers.put(Dice.class, new RepresentDice());
+ }
+
+ private class RepresentDice implements Represent {
+ public Node representData(Object data) {
+ Dice dice = (Dice) data;
+ String value = dice.getA() + "d" + dice.getB();
+ return representScalar("!dice", value);
+ }
+ }
+ }
+
+ class DiceConstructor extends Constructor {
+ public DiceConstructor() {
+ this.yamlConstructors.put("!dice", new ConstructDice());
+ }
+
+ private class ConstructDice implements Construct {
+ public Object construct(Node node) {
+ String val = (String) constructScalar((ScalarNode) node);
+ int position = val.indexOf('d');
+ Integer a = Integer.parseInt(val.substring(0, position));
+ Integer b = Integer.parseInt(val.substring(position + 1));
+ return new Dice(a, b);
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testConstructor() throws IOException {
+ Yaml yaml = new Yaml(new Loader(new DiceConstructor()));
+ Object data = yaml.load("{initial hit points: !dice '8d4'}");
+ Map<String, Dice> map = (Map<String, Dice>) data;
+ assertEquals(new Dice(8, 4), map.get("initial hit points"));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testImplicitResolver() throws IOException {
+ Yaml yaml = new Yaml(new Loader(new DiceConstructor()), new Dumper(new DiceRepresenter(),
+ new DumperOptions()));
+ yaml.addImplicitResolver("!dice", Pattern.compile("\\d+d\\d+"), "123456789");
+ // dump
+ Map<String, Dice> treasure = (Map<String, Dice>) new HashMap<String, Dice>();
+ treasure.put("treasure", new Dice(10, 20));
+ String output = yaml.dump(treasure);
+ System.out.println(output);
+ assertEquals("{treasure: 10d20}\n", output);
+ // load
+ Object data = yaml.load("{damage: 5d10}");
+ Map<String, Dice> map = (Map<String, Dice>) data;
+ assertEquals(new Dice(5, 10), map.get("damage"));
+ }
+}
diff --git a/src/test/java/examples/DumpExampleTest.java b/src/test/java/examples/DumpExampleTest.java new file mode 100644 index 00000000..e44ce842 --- /dev/null +++ b/src/test/java/examples/DumpExampleTest.java @@ -0,0 +1,128 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package examples;
+
+import java.io.StringWriter;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Yaml;
+
+public class DumpExampleTest extends TestCase {
+ public void testDump() {
+ Map<String, Object> data = new HashMap<String, Object>();
+ data.put("name", "Silenthand Olleander");
+ data.put("race", "Human");
+ data.put("traits", new String[] { "ONE_HAND", "ONE_EYE" });
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(data);
+ System.out.println(output);
+ assertTrue(output.contains("name: Silenthand Olleander"));
+ assertTrue(output.contains("race: Human"));
+ assertTrue(output.contains("traits: [ONE_HAND, ONE_EYE]"));
+ }
+
+ public void testDumpWriter() {
+ Map<String, Object> data = new HashMap<String, Object>();
+ data.put("name", "Silenthand Olleander");
+ data.put("race", "Human");
+ data.put("traits", new String[] { "ONE_HAND", "ONE_EYE" });
+ Yaml yaml = new Yaml();
+ StringWriter writer = new StringWriter();
+ yaml.dump(data, writer);
+ System.out.println(writer.toString());
+ assertTrue(writer.toString().contains("name: Silenthand Olleander"));
+ assertTrue(writer.toString().contains("race: Human"));
+ assertTrue(writer.toString().contains("traits: [ONE_HAND, ONE_EYE]"));
+ }
+
+ public void testDumpMany() {
+ List<Integer> docs = new LinkedList<Integer>();
+ for (int i = 1; i < 4; i++) {
+ docs.add(i);
+ }
+ DumperOptions options = new DumperOptions();
+ options.setExplicitStart(true);
+ Yaml yaml = new Yaml(options);
+ System.out.println(yaml.dump(docs));
+ System.out.println(yaml.dumpAll(docs.iterator()));
+ }
+
+ public void testDumpCustomJavaClass() {
+ Hero hero = new Hero("Galain Ysseleg", -3, 2);
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(hero);
+ System.out.println(output);
+ assertEquals("!!examples.Hero {hp: -3, name: Galain Ysseleg, sp: 2}\n", output);
+ }
+
+ public void testDumperOptions() {
+ List<Integer> data = new LinkedList<Integer>();
+ for (int i = 0; i < 50; i++) {
+ data.add(i);
+ }
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(data);
+ System.out.println(output);
+ assertTrue(output.contains("[0, 1, 2, 3, 4, 5, 6, 7, 8"));
+ //
+ DumperOptions options = new DumperOptions();
+ options.setWidth(50);
+ options.setIndent(4);
+ yaml = new Yaml(options);
+ output = yaml.dump(data);
+ System.out.println(output);
+ }
+
+ public void testDumperOptionsCanonical() {
+ List<Integer> data = new LinkedList<Integer>();
+ for (int i = 0; i < 5; i++) {
+ data.add(i);
+ }
+ DumperOptions options = new DumperOptions();
+ options.setCanonical(true);
+ Yaml yaml = new Yaml(options);
+ String output = yaml.dump(data);
+ System.out.println(output);
+ assertTrue(output.contains("---"));
+ assertTrue(output.contains("!!seq ["));
+ assertTrue(output.contains("!!int \"3\","));
+ }
+
+ public void testDumperOptionsFlowStyle() {
+ List<Integer> data = new LinkedList<Integer>();
+ for (int i = 0; i < 5; i++) {
+ data.add(i);
+ }
+ DumperOptions options = new DumperOptions();
+ options.setDefaultFlowStyle(DumperOptions.DefaultFlowStyle.BLOCK);
+ Yaml yaml = new Yaml(options);
+ String output = yaml.dump(data);
+ System.out.println(output);
+ assertTrue(output.contains("- 0\n"));
+ assertTrue(output.contains("- 1\n"));
+ assertTrue(output.contains("- 4\n"));
+ }
+
+ public void testDumperOptionsStyle() {
+ List<Integer> data = new LinkedList<Integer>();
+ for (int i = 0; i < 5; i++) {
+ data.add(i);
+ }
+ DumperOptions options = new DumperOptions();
+ options.setDefaultStyle(DumperOptions.DefaultScalarStyle.DOUBLE_QUOTED);
+ Yaml yaml = new Yaml(options);
+ String output = yaml.dump(data);
+ System.out.println(output);
+ assertTrue(output.contains("- !!int \"0\""));
+ assertTrue(output.contains("- !!int \"1\""));
+ assertTrue(output.contains("- !!int \"4\""));
+ }
+
+}
diff --git a/src/test/java/examples/Hero.java b/src/test/java/examples/Hero.java new file mode 100644 index 00000000..6cdf874a --- /dev/null +++ b/src/test/java/examples/Hero.java @@ -0,0 +1,30 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package examples;
+
+public class Hero {
+ private String name;
+ private Integer sp;
+ private Integer hp;
+
+ public Hero(String name, Integer hp, Integer sp) {
+ super();
+ this.name = name;
+ this.sp = sp;
+ this.hp = hp;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Integer getSp() {
+ return sp;
+ }
+
+ public Integer getHp() {
+ return hp;
+ }
+
+}
diff --git a/src/test/java/examples/LoadExampleTest.java b/src/test/java/examples/LoadExampleTest.java new file mode 100644 index 00000000..652c5d51 --- /dev/null +++ b/src/test/java/examples/LoadExampleTest.java @@ -0,0 +1,59 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package examples;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+
+public class LoadExampleTest extends TestCase {
+ @SuppressWarnings("unchecked")
+ public void testLoad() {
+ Yaml yaml = new Yaml();
+ String document = "\n- Hesperiidae\n- Papilionidae\n- Apatelodidae\n- Epiplemidae";
+ System.out.println(document);
+ List<String> list = (List<String>) yaml.load(document);
+ System.out.println(list);
+ assertEquals("[Hesperiidae, Papilionidae, Apatelodidae, Epiplemidae]", list.toString());
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testLoadFromString() {
+ Yaml yaml = new Yaml();
+ String document = "hello: 25";
+ Map map = (Map) yaml.load(document);
+ assertEquals("{hello=25}", map.toString());
+ assertEquals(new Integer(25), map.get("hello"));
+ }
+
+ public void testLoadFromStream() throws FileNotFoundException {
+ InputStream input = new FileInputStream(new File("src/test/resources/reader/utf-8.txt"));
+ Yaml yaml = new Yaml();
+ Object data = yaml.load(input);
+ assertEquals("test", data);
+ //
+ data = yaml.load(new ByteArrayInputStream("test2".getBytes()));
+ assertEquals("test2", data);
+ }
+
+ public void testLoadManyDocuments() throws FileNotFoundException {
+ InputStream input = new FileInputStream(new File(
+ "src/test/resources/specification/example2_28.yaml"));
+ Yaml yaml = new Yaml();
+ int counter = 0;
+ for (Object data : yaml.loadAll(input)) {
+ System.out.println(data);
+ counter++;
+ }
+ assertEquals(3, counter);
+ }
+}
diff --git a/src/test/java/examples/SafeConstructorExampleTest.java b/src/test/java/examples/SafeConstructorExampleTest.java new file mode 100644 index 00000000..34f5a7dd --- /dev/null +++ b/src/test/java/examples/SafeConstructorExampleTest.java @@ -0,0 +1,42 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package examples;
+
+import java.io.IOException;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Loader;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.SafeConstructor;
+
+public class SafeConstructorExampleTest extends TestCase {
+ @SuppressWarnings("unchecked")
+ public void testConstruct() throws IOException {
+ String doc = "- 5\n- Person\n- true";
+ Loader loader = new Loader(new SafeConstructor());
+ Yaml yaml = new Yaml(loader);
+ List<Object> list = (List<Object>) yaml.load(doc);
+ System.out.println(list);
+ assertEquals(3, list.size());
+ assertEquals(new Integer(5), list.get(0));
+ assertEquals("Person", list.get(1));
+ assertEquals(Boolean.TRUE, list.get(2));
+ }
+
+ public void testSafeConstruct() throws IOException {
+ String doc = "- 5\n- !org.yaml.snakeyaml.constructor.Person\n firstName: Andrey\n age: 99\n- true";
+ Loader loader = new Loader(new SafeConstructor());
+ Yaml yaml = new Yaml(loader);
+ try {
+ yaml.load(doc);
+ fail("Custom Java classes should not be created.");
+ } catch (Exception e) {
+ assertEquals(
+ "null; could not determine a constructor for the tag !org.yaml.snakeyaml.constructor.Person",
+ e.getMessage());
+ }
+ }
+}
diff --git a/src/test/java/examples/SpringTest.java b/src/test/java/examples/SpringTest.java new file mode 100644 index 00000000..fdead4fd --- /dev/null +++ b/src/test/java/examples/SpringTest.java @@ -0,0 +1,21 @@ +package examples;
+
+import junit.framework.TestCase;
+
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+import org.yaml.snakeyaml.Yaml;
+
+public class SpringTest extends TestCase {
+ public void testSimple() {
+ ApplicationContext context = new ClassPathXmlApplicationContext("examples/spring.xml");
+ Yaml yaml = (Yaml) context.getBean("standardYaml");
+ assertNotNull(yaml);
+ //
+ yaml = (Yaml) context.getBean("javabeanYaml");
+ assertNotNull(yaml);
+ //
+ yaml = (Yaml) context.getBean("snakeYaml");
+ assertNotNull(yaml);
+ }
+}
\ No newline at end of file diff --git a/src/test/java/org/pyyaml/AnInstance.java b/src/test/java/org/pyyaml/AnInstance.java new file mode 100644 index 00000000..655360dc --- /dev/null +++ b/src/test/java/org/pyyaml/AnInstance.java @@ -0,0 +1,34 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.pyyaml;
+
+public class AnInstance {
+ private Object foo;
+ private Object bar;
+
+ public AnInstance() {
+ }
+
+ public AnInstance(Object foo, Object bar) {
+ this.foo = foo;
+ this.bar = bar;
+ }
+
+ public Object getFoo() {
+ return foo;
+ }
+
+ public void setFoo(Object foo) {
+ this.foo = foo;
+ }
+
+ public Object getBar() {
+ return bar;
+ }
+
+ public void setBar(Object bar) {
+ this.bar = bar;
+ }
+
+}
\ No newline at end of file diff --git a/src/test/java/org/pyyaml/CanonicalException.java b/src/test/java/org/pyyaml/CanonicalException.java new file mode 100644 index 00000000..4bec5757 --- /dev/null +++ b/src/test/java/org/pyyaml/CanonicalException.java @@ -0,0 +1,19 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.pyyaml;
+
+import org.yaml.snakeyaml.error.YAMLException;
+
+public class CanonicalException extends YAMLException {
+
+ private static final long serialVersionUID = -6489045150083747626L;
+
+ public CanonicalException(String message) {
+ super(message);
+ }
+
+ public CanonicalException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/src/test/java/org/pyyaml/CanonicalLoader.java b/src/test/java/org/pyyaml/CanonicalLoader.java new file mode 100644 index 00000000..6d54306c --- /dev/null +++ b/src/test/java/org/pyyaml/CanonicalLoader.java @@ -0,0 +1,72 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.pyyaml;
+
+import java.io.IOException;
+import java.util.Iterator;
+
+import org.yaml.snakeyaml.Loader;
+import org.yaml.snakeyaml.composer.Composer;
+import org.yaml.snakeyaml.error.YAMLException;
+
+public class CanonicalLoader extends Loader {
+ @Override
+ public Object load(java.io.Reader yaml) {
+ try {
+ int ch = yaml.read();
+ StringBuffer buffer = new StringBuffer();
+ while (ch != -1) {
+ buffer.append((char) ch);
+ ch = yaml.read();
+ }
+ Composer composer = new Composer(new CanonicalParser(buffer.toString()), resolver);
+ constructor.setComposer(composer);
+ return constructor.getSingleData();
+ } catch (IOException e) {
+ throw new YAMLException(e);
+ }
+ }
+
+ public Iterable<Object> loadAll(java.io.Reader yaml) {
+ try {
+ int ch = yaml.read();
+ StringBuffer buffer = new StringBuffer();
+ while (ch != -1) {
+ buffer.append((char) ch);
+ ch = yaml.read();
+ }
+ Composer composer = new Composer(new CanonicalParser(buffer.toString()), resolver);
+ this.constructor.setComposer(composer);
+ Iterator<Object> result = new Iterator<Object>() {
+ public boolean hasNext() {
+ return constructor.checkData();
+ }
+
+ public Object next() {
+ return constructor.getData();
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ return new YamlIterable(result);
+ } catch (IOException e) {
+ throw new YAMLException(e);
+ }
+ }
+
+ private class YamlIterable implements Iterable<Object> {
+ private Iterator<Object> iterator;
+
+ public YamlIterable(Iterator<Object> iterator) {
+ this.iterator = iterator;
+ }
+
+ public Iterator<Object> iterator() {
+ return iterator;
+ }
+
+ }
+}
diff --git a/src/test/java/org/pyyaml/CanonicalParser.java b/src/test/java/org/pyyaml/CanonicalParser.java new file mode 100644 index 00000000..f3a302f3 --- /dev/null +++ b/src/test/java/org/pyyaml/CanonicalParser.java @@ -0,0 +1,198 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.pyyaml;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.yaml.snakeyaml.events.AliasEvent;
+import org.yaml.snakeyaml.events.DocumentEndEvent;
+import org.yaml.snakeyaml.events.DocumentStartEvent;
+import org.yaml.snakeyaml.events.Event;
+import org.yaml.snakeyaml.events.MappingEndEvent;
+import org.yaml.snakeyaml.events.MappingStartEvent;
+import org.yaml.snakeyaml.events.ScalarEvent;
+import org.yaml.snakeyaml.events.SequenceEndEvent;
+import org.yaml.snakeyaml.events.SequenceStartEvent;
+import org.yaml.snakeyaml.events.StreamEndEvent;
+import org.yaml.snakeyaml.events.StreamStartEvent;
+import org.yaml.snakeyaml.parser.Parser;
+import org.yaml.snakeyaml.tokens.AliasToken;
+import org.yaml.snakeyaml.tokens.AnchorToken;
+import org.yaml.snakeyaml.tokens.DirectiveToken;
+import org.yaml.snakeyaml.tokens.DocumentStartToken;
+import org.yaml.snakeyaml.tokens.FlowEntryToken;
+import org.yaml.snakeyaml.tokens.FlowMappingEndToken;
+import org.yaml.snakeyaml.tokens.FlowMappingStartToken;
+import org.yaml.snakeyaml.tokens.FlowSequenceEndToken;
+import org.yaml.snakeyaml.tokens.FlowSequenceStartToken;
+import org.yaml.snakeyaml.tokens.KeyToken;
+import org.yaml.snakeyaml.tokens.ScalarToken;
+import org.yaml.snakeyaml.tokens.StreamEndToken;
+import org.yaml.snakeyaml.tokens.StreamStartToken;
+import org.yaml.snakeyaml.tokens.TagToken;
+import org.yaml.snakeyaml.tokens.Token;
+import org.yaml.snakeyaml.tokens.ValueToken;
+
+public class CanonicalParser implements Parser {
+ private LinkedList<Event> events;
+ private boolean parsed;
+ private CanonicalScanner scanner;
+
+ public CanonicalParser(String data) {
+ events = new LinkedList<Event>();
+ parsed = false;
+ scanner = new CanonicalScanner(data);
+ }
+
+ // stream: STREAM-START document* STREAM-END
+ private void parseStream() {
+ scanner.getToken(StreamStartToken.class);
+ events.add(new StreamStartEvent(null, null));
+ while (!scanner.checkToken(StreamEndToken.class)) {
+ List<Class<? extends Token>> list = new ArrayList<Class<? extends Token>>();
+ list.add(DirectiveToken.class);
+ list.add(DocumentStartToken.class);
+ if (scanner.checkToken(list)) {
+ parseDocument();
+ } else {
+ throw new CanonicalException("document is expected, got " + scanner.tokens.get(0));
+ }
+ }
+ scanner.getToken(StreamEndToken.class);
+ events.add(new StreamEndEvent(null, null));
+ }
+
+ // document: DIRECTIVE? DOCUMENT-START node
+ private void parseDocument() {
+ if (scanner.checkToken(DirectiveToken.class)) {
+ scanner.getToken(DirectiveToken.class);
+ }
+ scanner.getToken(DocumentStartToken.class);
+ events.add(new DocumentStartEvent(null, null, true, new Integer[] { 1, 1 }, null));
+ parseNode();
+ events.add(new DocumentEndEvent(null, null, true));
+ }
+
+ // node: ALIAS | ANCHOR? TAG? (SCALAR|sequence|mapping)
+ private void parseNode() {
+ if (scanner.checkToken(AliasToken.class)) {
+ AliasToken token = (AliasToken) scanner.getToken();
+ events.add(new AliasEvent(token.getValue(), null, null));
+ } else {
+ String anchor = null;
+ if (scanner.checkToken(AnchorToken.class)) {
+ AnchorToken token = (AnchorToken) scanner.getToken();
+ anchor = token.getValue();
+ }
+ String tag = null;
+ if (scanner.checkToken(TagToken.class)) {
+ TagToken token = (TagToken) scanner.getToken();
+ tag = token.getValue()[0] + token.getValue()[1];
+ }
+ if (scanner.checkToken(ScalarToken.class)) {
+ ScalarToken token = (ScalarToken) scanner.getToken();
+ events.add(new ScalarEvent(anchor, tag, new boolean[] { false, false }, token
+ .getValue(), null, null, null));
+ } else if (scanner.checkToken(FlowSequenceStartToken.class)) {
+ events.add(new SequenceStartEvent(anchor, tag, false, null, null, null));
+ parseSequence();
+ } else if (scanner.checkToken(FlowMappingStartToken.class)) {
+ events.add(new MappingStartEvent(anchor, tag, false, null, null, null));
+ parseMapping();
+ } else {
+ throw new CanonicalException("SCALAR, '[', or '{' is expected, got "
+ + scanner.tokens.get(0));
+ }
+ }
+ }
+
+ // sequence: SEQUENCE-START (node (ENTRY node)*)? ENTRY? SEQUENCE-END
+ private void parseSequence() {
+ scanner.getToken(FlowSequenceStartToken.class);
+ if (!scanner.checkToken(FlowSequenceEndToken.class)) {
+ parseNode();
+ while (!scanner.checkToken(FlowSequenceEndToken.class)) {
+ scanner.getToken(FlowEntryToken.class);
+ if (!scanner.checkToken(FlowSequenceEndToken.class)) {
+ parseNode();
+ }
+ }
+ }
+ scanner.getToken(FlowSequenceEndToken.class);
+ events.add(new SequenceEndEvent(null, null));
+ }
+
+ // mapping: MAPPING-START (map_entry (ENTRY map_entry)*)? ENTRY? MAPPING-END
+ private void parseMapping() {
+ scanner.getToken(FlowMappingStartToken.class);
+ if (!scanner.checkToken(FlowMappingEndToken.class)) {
+ parseMapEntry();
+ while (!scanner.checkToken(FlowMappingEndToken.class)) {
+ scanner.getToken(FlowEntryToken.class);
+ if (!scanner.checkToken(FlowMappingEndToken.class)) {
+ parseMapEntry();
+ }
+ }
+ }
+ scanner.getToken(FlowMappingEndToken.class);
+ events.add(new MappingEndEvent(null, null));
+ }
+
+ // map_entry: KEY node VALUE node
+ private void parseMapEntry() {
+ scanner.getToken(KeyToken.class);
+ parseNode();
+ scanner.getToken(ValueToken.class);
+ parseNode();
+ }
+
+ public void parse() {
+ parseStream();
+ parsed = true;
+ }
+
+ public Event getEvent() {
+ if (!parsed) {
+ parse();
+ }
+ return events.removeFirst();
+ }
+
+ public boolean checkEvent(List<Class<? extends Event>> choices) {
+ if (!parsed) {
+ parse();
+ }
+ if (!events.isEmpty()) {
+ if (choices.isEmpty()) {
+ return true;
+ }
+ for (Class<? extends Event> class1 : choices) {
+ if (class1.isInstance(events.peek())) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public boolean checkEvent(Class<? extends Event> choice) {
+ List<Class<? extends Event>> list = new ArrayList<Class<? extends Event>>(1);
+ list.add(choice);
+ return checkEvent(list);
+ }
+
+ public Event peekEvent() {
+ if (!parsed) {
+ parse();
+ }
+ if (events.isEmpty()) {
+ return null;
+ } else {
+ return events.get(0);
+ }
+ }
+
+}
diff --git a/src/test/java/org/pyyaml/CanonicalScanner.java b/src/test/java/org/pyyaml/CanonicalScanner.java new file mode 100644 index 00000000..146cdf98 --- /dev/null +++ b/src/test/java/org/pyyaml/CanonicalScanner.java @@ -0,0 +1,301 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.pyyaml;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.yaml.snakeyaml.error.Mark;
+import org.yaml.snakeyaml.scanner.Scanner;
+import org.yaml.snakeyaml.scanner.ScannerImpl;
+import org.yaml.snakeyaml.tokens.AliasToken;
+import org.yaml.snakeyaml.tokens.AnchorToken;
+import org.yaml.snakeyaml.tokens.DirectiveToken;
+import org.yaml.snakeyaml.tokens.DocumentStartToken;
+import org.yaml.snakeyaml.tokens.FlowEntryToken;
+import org.yaml.snakeyaml.tokens.FlowMappingEndToken;
+import org.yaml.snakeyaml.tokens.FlowMappingStartToken;
+import org.yaml.snakeyaml.tokens.FlowSequenceEndToken;
+import org.yaml.snakeyaml.tokens.FlowSequenceStartToken;
+import org.yaml.snakeyaml.tokens.KeyToken;
+import org.yaml.snakeyaml.tokens.ScalarToken;
+import org.yaml.snakeyaml.tokens.StreamEndToken;
+import org.yaml.snakeyaml.tokens.StreamStartToken;
+import org.yaml.snakeyaml.tokens.TagToken;
+import org.yaml.snakeyaml.tokens.Token;
+import org.yaml.snakeyaml.tokens.ValueToken;
+
+public class CanonicalScanner implements Scanner {
+ private static final String DIRECTIVE = "%YAML 1.1";
+ private final static Map<Character, Integer> QUOTE_CODES = ScannerImpl.ESCAPE_CODES;
+
+ private final static Map<Character, String> QUOTE_REPLACES = ScannerImpl.ESCAPE_REPLACEMENTS;
+
+ private String data;
+ private int index;
+ public LinkedList<Token> tokens;
+ private boolean scanned;
+ private Mark mark;
+
+ public CanonicalScanner(String data) {
+ this.data = data + "\0";
+ this.index = 0;
+ this.tokens = new LinkedList<Token>();
+ this.scanned = false;
+ this.mark = new Mark("test", 0, 0, 0, data, 0);
+ }
+
+ public boolean checkToken(List<Class<? extends Token>> choices) {
+ if (!scanned) {
+ scan();
+ }
+ if (!tokens.isEmpty()) {
+ if (choices.isEmpty()) {
+ return true;
+ }
+ Token first = this.tokens.get(0);
+ for (Class<? extends Token> choice : choices) {
+ if (choice.isInstance(first)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public boolean checkToken(Class<? extends Token> choice) {
+ List<Class<? extends Token>> list = new ArrayList<Class<? extends Token>>();
+ list.add(choice);
+ return checkToken(list);
+ }
+
+ public Token peekToken() {
+ if (!scanned) {
+ scan();
+ }
+ if (!tokens.isEmpty()) {
+ Token first = this.tokens.get(0);
+ return first;
+ }
+ return null;
+ }
+
+ public Token getToken() {
+ if (!scanned) {
+ scan();
+ }
+ Token token = this.tokens.poll();
+ return token;
+ }
+
+ public Token getToken(Class<? extends Token> choice) {
+ Token token = getToken();
+ if (choice != null && !choice.isInstance(token)) {
+ throw new CanonicalException("unexpected token " + token);
+ }
+ return token;
+ }
+
+ private void scan() {
+ this.tokens.add(new StreamStartToken(mark, mark));
+ boolean stop = false;
+ while (!stop) {
+ findToken();
+ char ch = data.charAt(index);
+ switch (ch) {
+ case '\0':
+ tokens.add(new StreamEndToken(mark, mark));
+ stop = true;
+ break;
+
+ case '%':
+ tokens.add(scanDirective());
+ break;
+
+ case '-':
+ if ("---".equals(data.substring(index, index + 3))) {
+ index += 3;
+ tokens.add(new DocumentStartToken(mark, mark));
+ }
+ break;
+
+ case '[':
+ index++;
+ tokens.add(new FlowSequenceStartToken(mark, mark));
+ break;
+
+ case '{':
+ index++;
+ tokens.add(new FlowMappingStartToken(mark, mark));
+ break;
+
+ case ']':
+ index++;
+ tokens.add(new FlowSequenceEndToken(mark, mark));
+ break;
+
+ case '}':
+ index++;
+ tokens.add(new FlowMappingEndToken(mark, mark));
+ break;
+
+ case '?':
+ index++;
+ tokens.add(new KeyToken(mark, mark));
+ break;
+
+ case ':':
+ index++;
+ tokens.add(new ValueToken(mark, mark));
+ break;
+
+ case ',':
+ index++;
+ tokens.add(new FlowEntryToken(mark, mark));
+ break;
+
+ case '*':
+ tokens.add(scanAlias());
+ break;
+
+ case '&':
+ tokens.add(scanAlias());
+ break;
+
+ case '!':
+ tokens.add(scanTag());
+ break;
+
+ case '"':
+ tokens.add(scanScalar());
+ break;
+
+ default:
+ throw new CanonicalException("invalid token");
+ }
+ }
+ scanned = true;
+ }
+
+ private Token scanDirective() {
+ String chunk1 = data.substring(index, index + DIRECTIVE.length());
+ char chunk2 = data.charAt(index + DIRECTIVE.length());
+ if (DIRECTIVE.equals(chunk1) && "\n\0".indexOf(chunk2) != -1) {
+ index += DIRECTIVE.length();
+ List<Integer> implicit = new ArrayList<Integer>(2);
+ implicit.add(new Integer(1));
+ implicit.add(new Integer(1));
+ return new DirectiveToken("YAML", implicit, mark, mark);
+ } else {
+ throw new CanonicalException("invalid directive");
+ }
+ }
+
+ private Token scanAlias() {
+ boolean isTokenClassAlias;
+ if (data.charAt(index) == '*') {
+ isTokenClassAlias = true;
+ } else {
+ isTokenClassAlias = false;
+ }
+ index++;
+ int start = index;
+ while (", \n\0".indexOf(data.charAt(index)) == -1) {
+ index++;
+ }
+ String value = data.substring(start, index);
+ Token token;
+ if (isTokenClassAlias) {
+ token = new AliasToken(value, mark, mark);
+ } else {
+ token = new AnchorToken(value, mark, mark);
+ }
+ return token;
+ }
+
+ private Token scanTag() {
+ index++;
+ int start = index;
+ while (" \n\0".indexOf(data.charAt(index)) == -1) {
+ index++;
+ }
+ String value = data.substring(start, index);
+ if (value.length() == 0) {
+ value = "!";
+ } else if (value.charAt(0) == '!') {
+ value = "tag:yaml.org,2002:" + value.substring(1);
+ } else if (value.charAt(0) == '<' && value.charAt(value.length() - 1) == '>') {
+ value = value.substring(1, value.length() - 1);
+ } else {
+ value = "!" + value;
+ }
+ return new TagToken(new String[] { "", value }, mark, mark);
+ }
+
+ private Token scanScalar() {
+ index++;
+ StringBuffer chunks = new StringBuffer();
+ int start = index;
+ boolean ignoreSpaces = false;
+ while (data.charAt(index) != '"') {
+ if (data.charAt(index) == '\\') {
+ ignoreSpaces = false;
+ chunks.append(data.substring(start, index));
+ index++;
+ char ch = data.charAt(index);
+ index++;
+ if (ch == '\n') {
+ ignoreSpaces = true;
+ } else if (QUOTE_CODES.keySet().contains(ch)) {
+ int length = QUOTE_CODES.get(ch);
+ int code = Integer.parseInt(data.substring(index, index + length), 16);
+ chunks.append(String.valueOf((char) code));
+ index += length;
+ } else {
+ if (!QUOTE_REPLACES.keySet().contains(ch)) {
+ throw new CanonicalException("invalid escape code");
+ }
+ chunks.append(QUOTE_REPLACES.get(ch));
+ }
+ start = index;
+ } else if (data.charAt(index) == '\n') {
+ chunks.append(data.substring(start, index));
+ chunks.append(" ");
+ index++;
+ start = index;
+ ignoreSpaces = true;
+ } else if (ignoreSpaces && data.charAt(index) == ' ') {
+ index++;
+ start = index;
+ } else {
+ ignoreSpaces = false;
+ index++;
+ }
+ }
+ chunks.append(data.substring(start, index));
+ index++;
+ return new ScalarToken(chunks.toString(), mark, mark, false);
+ }
+
+ private void findToken() {
+ boolean found = false;
+ while (!found) {
+ while (" \t".indexOf(data.charAt(index)) != -1) {
+ index++;
+ }
+ if (data.charAt(index) == '#') {
+ while (data.charAt(index) != '\n') {
+ index++;
+ }
+ }
+ if (data.charAt(index) == '\n') {
+ index++;
+ } else {
+ found = true;
+ }
+ }
+ }
+}
diff --git a/src/test/java/org/pyyaml/PyCanonicalTest.java b/src/test/java/org/pyyaml/PyCanonicalTest.java new file mode 100644 index 00000000..41a9e8e2 --- /dev/null +++ b/src/test/java/org/pyyaml/PyCanonicalTest.java @@ -0,0 +1,53 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.pyyaml;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.yaml.snakeyaml.events.Event;
+import org.yaml.snakeyaml.tokens.Token;
+
+/**
+ * @see imported from PyYAML
+ */
+public class PyCanonicalTest extends PyImportTest {
+
+ public void testCanonicalScanner() throws IOException {
+ File[] files = getStreamsByExtension(".canonical");
+ assertTrue("No test files found.", files.length > 0);
+ for (int i = 0; i < files.length; i++) {
+ List<Token> tokens = canonicalScan(new FileInputStream(files[i]));
+ assertFalse(tokens.isEmpty());
+ }
+ }
+
+ private List<Token> canonicalScan(InputStream input) throws IOException {
+ int ch = input.read();
+ StringBuffer buffer = new StringBuffer();
+ while (ch != -1) {
+ buffer.append((char) ch);
+ ch = input.read();
+ }
+ CanonicalScanner scanner = new CanonicalScanner(buffer.toString());
+ List<Token> result = new LinkedList<Token>();
+ while (scanner.peekToken() != null) {
+ result.add(scanner.getToken());
+ }
+ return result;
+ }
+
+ public void testCanonicalParser() throws IOException {
+ File[] files = getStreamsByExtension(".canonical");
+ assertTrue("No test files found.", files.length > 0);
+ for (int i = 0; i < files.length; i++) {
+ List<Event> tokens = canonicalParse(new FileInputStream(files[i]));
+ assertFalse(tokens.isEmpty());
+ }
+ }
+}
diff --git a/src/test/java/org/pyyaml/PyEmitterTest.java b/src/test/java/org/pyyaml/PyEmitterTest.java new file mode 100644 index 00000000..f2de9a65 --- /dev/null +++ b/src/test/java/org/pyyaml/PyEmitterTest.java @@ -0,0 +1,284 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.pyyaml;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Loader;
+import org.yaml.snakeyaml.emitter.Emitter;
+import org.yaml.snakeyaml.emitter.EventsLoader;
+import org.yaml.snakeyaml.events.CollectionStartEvent;
+import org.yaml.snakeyaml.events.Event;
+import org.yaml.snakeyaml.events.MappingStartEvent;
+import org.yaml.snakeyaml.events.NodeEvent;
+import org.yaml.snakeyaml.events.ScalarEvent;
+import org.yaml.snakeyaml.events.SequenceStartEvent;
+import org.yaml.snakeyaml.parser.Parser;
+import org.yaml.snakeyaml.parser.ParserImpl;
+import org.yaml.snakeyaml.reader.Reader;
+import org.yaml.snakeyaml.reader.UnicodeReader;
+
+/**
+ * @see imported from PyYAML
+ */
+public class PyEmitterTest extends PyImportTest {
+ public void testEmitterOnData() throws IOException {
+ _testEmitter(".data", false);
+ }
+
+ public void testEmitterOnCanonicalNormally() throws IOException {
+ _testEmitter(".canonical", false);
+ }
+
+ public void testEmitterOnCanonicalCanonically() throws IOException {
+ _testEmitter(".canonical", true);
+ }
+
+ private void _testEmitter(String mask, boolean canonical) throws IOException {
+ File[] files = getStreamsByExtension(mask, true);
+ assertTrue("No test files found.", files.length > 0);
+ for (File file : files) {
+ // if (!file.getName().contains("spec-06-01.canonical")) {
+ // continue;
+ // }
+ try {
+ List<Event> events = parse(new FileInputStream(file));
+ //
+ StringWriter stream = new StringWriter();
+ DumperOptions options = new DumperOptions();
+ options.setCanonical(canonical);
+ Emitter emitter = new Emitter(stream, options);
+ for (Event event : events) {
+ emitter.emit(event);
+ }
+ //
+ String data = stream.toString();
+ List<Event> newEvents = new LinkedList<Event>();
+ Reader reader = new Reader(data);
+ Parser parser = new ParserImpl(reader);
+ while (parser.peekEvent() != null) {
+ Event event = parser.getEvent();
+ newEvents.add(event);
+ }
+ // check
+ assertEquals(events.size(), newEvents.size());
+ Iterator<Event> iter1 = events.iterator();
+ Iterator<Event> iter2 = newEvents.iterator();
+ while (iter1.hasNext()) {
+ Event event = iter1.next();
+ Event newEvent = iter2.next();
+ assertEquals(event.getClass().getName(), newEvent.getClass().getName());
+ if (event instanceof NodeEvent) {
+ NodeEvent e1 = (NodeEvent) event;
+ NodeEvent e2 = (NodeEvent) newEvent;
+ assertEquals(e1.getAnchor(), e2.getAnchor());
+ }
+ if (event instanceof CollectionStartEvent) {
+ CollectionStartEvent e1 = (CollectionStartEvent) event;
+ CollectionStartEvent e2 = (CollectionStartEvent) newEvent;
+ assertEquals(e1.getTag(), e2.getTag());
+ }
+ if (event instanceof ScalarEvent) {
+ ScalarEvent e1 = (ScalarEvent) event;
+ ScalarEvent e2 = (ScalarEvent) newEvent;
+ boolean[] implicit1 = e1.getImplicit();
+ boolean[] implicit2 = e2.getImplicit();
+ if (!implicit1[0] && !implicit1[1] && !implicit2[0] && !implicit2[1]) {
+ assertEquals(e1.getTag(), e2.getTag());
+ }
+ assertEquals(e1.getValue(), e2.getValue());
+ }
+ }
+ } catch (Exception e) {
+ System.out.println("Failed File: " + file);
+ // fail("Failed File: " + file + "; " + e.getMessage());
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testEmitterStyles() throws IOException {
+ File[] canonicalFiles = getStreamsByExtension(".canonical", false);
+ assertTrue("No test files found.", canonicalFiles.length > 0);
+ File[] dataFiles = getStreamsByExtension(".data", true);
+ assertTrue("No test files found.", dataFiles.length > 0);
+ List<File> allFiles = new LinkedList(Arrays.asList(canonicalFiles));
+ allFiles.addAll(Arrays.asList(dataFiles));
+ for (File file : allFiles) {
+ try {
+ List<Event> events = new LinkedList<Event>();
+ Reader reader = new Reader(new UnicodeReader(new FileInputStream(file)));
+ Parser parser = new ParserImpl(reader);
+ while (parser.peekEvent() != null) {
+ Event event = parser.getEvent();
+ events.add(event);
+ }
+ //
+ for (Boolean flowStyle : new Boolean[] { Boolean.FALSE, Boolean.TRUE }) {
+ for (DumperOptions.DefaultScalarStyle style : DumperOptions.DefaultScalarStyle
+ .values()) {
+ List<Event> styledEvents = new LinkedList<Event>();
+ for (Event event : events) {
+ if (event instanceof ScalarEvent) {
+ ScalarEvent scalar = (ScalarEvent) event;
+ event = new ScalarEvent(scalar.getAnchor(), scalar.getTag(), scalar
+ .getImplicit(), scalar.getValue(), scalar.getStartMark(),
+ scalar.getEndMark(), style.getChar());
+ } else if (event instanceof SequenceStartEvent) {
+ SequenceStartEvent seqStart = (SequenceStartEvent) event;
+ event = new SequenceStartEvent(seqStart.getAnchor(), seqStart
+ .getTag(), seqStart.getImplicit(), seqStart.getStartMark(),
+ seqStart.getEndMark(), flowStyle);
+ } else if (event instanceof MappingStartEvent) {
+ MappingStartEvent mapStart = (MappingStartEvent) event;
+ event = new MappingStartEvent(mapStart.getAnchor(), mapStart
+ .getTag(), mapStart.getImplicit(), mapStart.getStartMark(),
+ mapStart.getEndMark(), flowStyle);
+ }
+ styledEvents.add(event);
+ }
+ // emit
+ String data = emit(styledEvents);
+ List<Event> newEvents = parse(data);
+ assertEquals("Events must not change. File: " + file, events.size(),
+ newEvents.size());
+ Iterator<Event> oldIter = events.iterator();
+ Iterator<Event> newIter = newEvents.iterator();
+ while (oldIter.hasNext()) {
+ Event event = oldIter.next();
+ Event newEvent = newIter.next();
+ assertEquals(event.getClass(), newEvent.getClass());
+ if (event instanceof NodeEvent) {
+ assertEquals(((NodeEvent) event).getAnchor(),
+ ((NodeEvent) newEvent).getAnchor());
+ }
+ if (event instanceof CollectionStartEvent) {
+ assertEquals(((CollectionStartEvent) event).getTag(),
+ ((CollectionStartEvent) newEvent).getTag());
+ }
+ if (event instanceof ScalarEvent) {
+ ScalarEvent scalarOld = (ScalarEvent) event;
+ ScalarEvent scalarNew = (ScalarEvent) newEvent;
+ boolean[] oldImplicit = scalarOld.getImplicit();
+ boolean[] newImplicit = scalarNew.getImplicit();
+ if (!oldImplicit[0] && !oldImplicit[1] && !newImplicit[0]
+ && !newImplicit[1]) {
+ assertEquals(scalarOld.getTag(), scalarNew.getTag());
+ }
+ assertEquals(scalarOld.getValue(), scalarNew.getValue());
+ }
+ }
+ }
+ }
+
+ } catch (Exception e) {
+ System.out.println("Failed File: " + file);
+ // fail("Failed File: " + file + "; " + e.getMessage());
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ private String emit(List<Event> events) throws IOException {
+ StringWriter writer = new StringWriter();
+ Emitter emitter = new Emitter(writer, new DumperOptions());
+ for (Event event : events) {
+ emitter.emit(event);
+ }
+ return writer.toString();
+ }
+
+ private List<Event> parse(String data) {
+ ParserImpl parser = new ParserImpl(new Reader(data));
+ List<Event> newEvents = new LinkedList<Event>();
+ while (parser.peekEvent() != null) {
+ newEvents.add(parser.getEvent());
+ }
+ return newEvents;
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testEmitterEvents() throws IOException {
+ File[] files = getStreamsByExtension(".events", false);
+ assertTrue("No test files found.", files.length > 0);
+ for (File file : files) {
+ // if (!file.getName().contains("spec-06-01.canonical")) {
+ // continue;
+ // }
+ try {
+ Loader loader = new EventsLoader();
+ List<Event> events = new LinkedList<Event>();
+ String content = getResource(file.getName());
+ events = (List<Event>) load(loader, content);
+ //
+ StringWriter stream = new StringWriter();
+ Emitter emitter = new Emitter(stream, new DumperOptions());
+ for (Event event : events) {
+ emitter.emit(event);
+ }
+ //
+ String data = stream.toString();
+ List<Event> newEvents = new LinkedList<Event>();
+ Reader reader = new Reader(data);
+ Parser parser = new ParserImpl(reader);
+ while (parser.peekEvent() != null) {
+ Event event = parser.getEvent();
+ newEvents.add(event);
+ }
+ // check
+ assertEquals(events.size(), newEvents.size());
+ Iterator<Event> iter1 = events.iterator();
+ Iterator<Event> iter2 = newEvents.iterator();
+ while (iter1.hasNext()) {
+ Event event = iter1.next();
+ Event newEvent = iter2.next();
+ assertEquals(event.getClass().getName(), newEvent.getClass().getName());
+ if (event instanceof NodeEvent) {
+ NodeEvent e1 = (NodeEvent) event;
+ NodeEvent e2 = (NodeEvent) newEvent;
+ assertEquals(e1.getAnchor(), e2.getAnchor());
+ }
+ if (event instanceof CollectionStartEvent) {
+ CollectionStartEvent e1 = (CollectionStartEvent) event;
+ CollectionStartEvent e2 = (CollectionStartEvent) newEvent;
+ assertEquals(e1.getTag(), e2.getTag());
+ }
+ if (event instanceof ScalarEvent) {
+ ScalarEvent e1 = (ScalarEvent) event;
+ ScalarEvent e2 = (ScalarEvent) newEvent;
+ boolean[] implicit1 = e1.getImplicit();
+ boolean[] implicit2 = e2.getImplicit();
+ if (implicit1[0] == implicit2[0] && implicit1[1] == implicit2[1]) {
+
+ } else {
+ if ((e1.getTag() == null || e2.getTag() == null)
+ || e1.getTag().equals(e2.getTag())) {
+
+ } else {
+ System.out.println("tag1: " + e1.getTag());
+ System.out.println("tag2: " + e2.getTag());
+ fail("in file: " + file);
+ }
+ }
+ assertEquals(e1.getValue(), e2.getValue());
+ }
+ }
+ } catch (Exception e) {
+ System.out.println("Failed File: " + file);
+ // fail("Failed File: " + file + "; " + e.getMessage());
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+}
diff --git a/src/test/java/org/pyyaml/PyErrorsTest.java b/src/test/java/org/pyyaml/PyErrorsTest.java new file mode 100644 index 00000000..8eb46962 --- /dev/null +++ b/src/test/java/org/pyyaml/PyErrorsTest.java @@ -0,0 +1,120 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.pyyaml;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Loader;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.emitter.Emitter;
+import org.yaml.snakeyaml.emitter.EventConstructor;
+import org.yaml.snakeyaml.error.YAMLException;
+import org.yaml.snakeyaml.events.Event;
+
+/**
+ * @see imported from PyYAML
+ */
+public class PyErrorsTest extends PyImportTest {
+ private boolean skip(String filename) {
+ List<String> failures = new ArrayList<String>();
+ // in python list cannot be a key in a dictionary.
+ failures.add("unacceptable-key.loader-error");
+ for (String name : failures) {
+ if (name.equals(filename)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public void testLoaderErrors() throws FileNotFoundException {
+ File[] files = getStreamsByExtension(".loader-error");
+ assertTrue("No test files found.", files.length > 0);
+ for (int i = 0; i < files.length; i++) {
+ if (skip(files[i].getName())) {
+ continue;
+ }
+ try {
+ for (Object document : loadAll(new FileInputStream(files[i]))) {
+ assertNotNull("File " + files[i], document);
+ }
+ fail("Loading must fail for " + files[i].getAbsolutePath());
+ // System.err.println("Loading must fail for " +
+ // files[i].getAbsolutePath());
+ } catch (Exception e) {
+ assertTrue(true);
+ }
+ }
+ }
+
+ public void testLoaderStringErrors() throws FileNotFoundException {
+ File[] files = getStreamsByExtension(".loader-error");
+ assertTrue("No test files found.", files.length > 0);
+ for (int i = 0; i < files.length; i++) {
+ if (skip(files[i].getName())) {
+ continue;
+ }
+ try {
+ String content = getResource(files[i].getName());
+ for (Object document : loadAll(content.trim())) {
+ assertNotNull(document);
+ }
+ fail("Loading must fail for " + files[i].getAbsolutePath());
+ // System.err.println("Loading must fail for " +
+ // files[i].getAbsolutePath());
+ } catch (Exception e) {
+ assertTrue(true);
+ }
+ }
+ }
+
+ public void testLoaderSingleErrors() throws FileNotFoundException {
+ File[] files = getStreamsByExtension(".single-loader-error");
+ assertTrue("No test files found.", files.length > 0);
+ for (int i = 0; i < files.length; i++) {
+ try {
+ String content = getResource(files[i].getName());
+ load(content.trim());
+ fail("Loading must fail for " + files[i].getAbsolutePath());
+ // multiple documents must not be accepted
+ System.err.println("Loading must fail for " + files[i].getAbsolutePath());
+ } catch (YAMLException e) {
+ assertTrue(true);
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testEmitterErrors() {
+ File[] files = getStreamsByExtension(".emitter-error");
+ assertTrue("No test files found.", files.length > 0);
+ for (int i = 0; i < files.length; i++) {
+ Constructor constructor = new EventConstructor();
+ Loader loader = new Loader(constructor);
+ String content = getResource(files[i].getName());
+ List<Event> document = (List<Event>) load(loader, content.trim());
+ Writer writer = new StringWriter();
+ Emitter emitter = new Emitter(writer, new DumperOptions());
+ try {
+ for (Event event : document) {
+ emitter.emit(event);
+ }
+ fail("Loading must fail for " + files[i].getAbsolutePath());
+ // System.err.println("Loading must fail for " +
+ // files[i].getAbsolutePath());
+ } catch (Exception e) {
+ assertTrue(true);
+ }
+ }
+ }
+
+ // testDumperErrors() is implemented in SerializerTest.java
+}
diff --git a/src/test/java/org/pyyaml/PyImportTest.java b/src/test/java/org/pyyaml/PyImportTest.java new file mode 100644 index 00000000..5bc7fe77 --- /dev/null +++ b/src/test/java/org/pyyaml/PyImportTest.java @@ -0,0 +1,128 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.pyyaml;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.LinkedList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Loader;
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.events.Event;
+import org.yaml.snakeyaml.parser.Parser;
+import org.yaml.snakeyaml.parser.ParserImpl;
+import org.yaml.snakeyaml.reader.Reader;
+import org.yaml.snakeyaml.reader.UnicodeReader;
+
+public abstract class PyImportTest extends TestCase {
+ public static final String PATH = "pyyaml";
+
+ protected Object load(String data) {
+ Yaml yaml = new Yaml();
+ Object obj = yaml.load(data);
+ return obj;
+ }
+
+ protected Object load(Loader loader, String data) {
+ Yaml yaml = new Yaml(loader);
+ Object obj = yaml.load(data);
+ return obj;
+ }
+
+ protected Iterable<Object> loadAll(InputStream data) {
+ Yaml yaml = new Yaml();
+ return yaml.loadAll(data);
+ }
+
+ protected Iterable<Object> loadAll(String data) {
+ Yaml yaml = new Yaml();
+ return yaml.loadAll(data);
+ }
+
+ protected Iterable<Object> loadAll(Loader loader, String data) {
+ Yaml yaml = new Yaml(loader);
+ return yaml.loadAll(data);
+ }
+
+ protected String getResource(String theName) {
+ try {
+ String content;
+ content = Util.getLocalResource(PATH + File.separator + theName);
+ return content;
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ protected File[] getStreamsByExtension(String extention) {
+ return getStreamsByExtension(extention, false);
+ }
+
+ protected File[] getStreamsByExtension(String extention, boolean onlyIfCanonicalPresent) {
+ File file = new File("src/test/resources/pyyaml");
+ assertTrue("Folder not found: " + file.getAbsolutePath(), file.exists());
+ assertTrue(file.isDirectory());
+ File[] files = file.listFiles(new PyFilenameFilter(extention, onlyIfCanonicalPresent));
+ return files;
+ }
+
+ protected File getFileByName(String name) {
+ File file = new File("src/test/resources/pyyaml/" + name);
+ assertTrue("Folder not found: " + file.getAbsolutePath(), file.exists());
+ assertTrue(file.isFile());
+ return file;
+ }
+
+ protected List<Event> canonicalParse(InputStream input2) throws IOException {
+ Reader reader = new Reader(new UnicodeReader(input2));
+ StringBuffer buffer = new StringBuffer();
+ while (reader.peek() != '\0') {
+ buffer.append(reader.peek());
+ reader.forward();
+ }
+ CanonicalParser parser = new CanonicalParser(buffer.toString());
+ List<Event> result = new LinkedList<Event>();
+ while (parser.peekEvent() != null) {
+ result.add(parser.getEvent());
+ }
+ return result;
+ }
+
+ protected List<Event> parse(InputStream input) throws IOException {
+ Reader reader = new Reader(new UnicodeReader(input));
+ Parser parser = new ParserImpl(reader);
+ List<Event> result = new LinkedList<Event>();
+ while (parser.peekEvent() != null) {
+ result.add(parser.getEvent());
+ }
+ return result;
+ }
+
+ private class PyFilenameFilter implements FilenameFilter {
+ private String extension;
+ private boolean onlyIfCanonicalPresent;
+
+ public PyFilenameFilter(String extension, boolean onlyIfCanonicalPresent) {
+ this.extension = extension;
+ this.onlyIfCanonicalPresent = onlyIfCanonicalPresent;
+ }
+
+ public boolean accept(File dir, String name) {
+ int position = name.lastIndexOf('.');
+ String canonicalFileName = name.substring(0, position) + ".canonical";
+ File canonicalFile = new File(dir, canonicalFileName);
+ if (onlyIfCanonicalPresent && !canonicalFile.exists()) {
+ return false;
+ } else {
+ return name.endsWith(extension);
+ }
+ }
+ }
+}
diff --git a/src/test/java/org/pyyaml/PyMarkTest.java b/src/test/java/org/pyyaml/PyMarkTest.java new file mode 100644 index 00000000..fe078385 --- /dev/null +++ b/src/test/java/org/pyyaml/PyMarkTest.java @@ -0,0 +1,45 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.pyyaml;
+
+import org.yaml.snakeyaml.error.Mark;
+
+/**
+ * @see imported from PyYAML
+ */
+public class PyMarkTest extends PyImportTest {
+
+ public void testMarks() {
+ String content = getResource("test_mark.marks");
+ String[] inputs = content.split("---\n");
+ for (int i = 1; i < inputs.length; i++) {
+ String input = inputs[i];
+ int index = 0;
+ int line = 0;
+ int column = 0;
+ while (input.charAt(index) != '*') {
+ if (input.charAt(index) != '\n') {
+ line += 1;
+ column = 0;
+ } else {
+ column += 1;
+ }
+ index += 1;
+ }
+ Mark mark = new Mark("testMarks", index, line, column, input, index);
+ String snippet = mark.get_snippet(2, 79);
+ assertTrue("Must only have one '\n'.", snippet.indexOf("\n") > -1);
+ assertEquals("Must only have only one '\n'.", snippet.indexOf("\n"), snippet
+ .lastIndexOf("\n"));
+ String[] lines = snippet.split("\n");
+ String data = lines[0];
+ String pointer = lines[1];
+ assertTrue("Mark must be restricted: " + data, data.length() < 82);
+ int dataPosition = data.indexOf("*");
+ int pointerPosition = pointer.indexOf("^");
+ assertEquals("Pointer should coincide with '*':\n " + snippet, dataPosition,
+ pointerPosition);
+ }
+ }
+}
diff --git a/src/test/java/org/pyyaml/PyReaderTest.java b/src/test/java/org/pyyaml/PyReaderTest.java new file mode 100644 index 00000000..c9891d76 --- /dev/null +++ b/src/test/java/org/pyyaml/PyReaderTest.java @@ -0,0 +1,36 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.pyyaml;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+
+import org.yaml.snakeyaml.reader.Reader;
+import org.yaml.snakeyaml.reader.ReaderException;
+import org.yaml.snakeyaml.reader.UnicodeReader;
+
+/**
+ * @see imported from PyYAML
+ */
+public class PyReaderTest extends PyImportTest {
+
+ public void testReaderUnicodeErrors() throws IOException {
+ File[] inputs = getStreamsByExtension(".stream-error");
+ for (int i = 0; i < inputs.length; i++) {
+ Reader stream = new Reader(new UnicodeReader(new FileInputStream(inputs[i])));
+ try {
+ while (stream.peek() != '\u0000') {
+ stream.forward();
+ }
+ fail("Invalid stream must not be accepted: " + inputs[i].getAbsolutePath()
+ + "; encoding=" + stream.getEncoding());
+ } catch (ReaderException e) {
+ System.out.println(e.toString());
+ assertTrue(true);
+ }
+ }
+ }
+
+}
diff --git a/src/test/java/org/pyyaml/PyRecursiveTest.java b/src/test/java/org/pyyaml/PyRecursiveTest.java new file mode 100644 index 00000000..14fb5d51 --- /dev/null +++ b/src/test/java/org/pyyaml/PyRecursiveTest.java @@ -0,0 +1,63 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.pyyaml;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.ConstructorException;
+
+public class PyRecursiveTest extends TestCase {
+
+ @SuppressWarnings("unchecked")
+ public void testDict() {
+ Map<AnInstance, AnInstance> value = new HashMap<AnInstance, AnInstance>();
+ AnInstance instance = new AnInstance(value, value);
+ value.put(instance, instance);
+ Yaml yaml = new Yaml();
+ try {
+ String output1 = yaml.dump(value);
+ Map<AnInstance, AnInstance> value2 = (Map<AnInstance, AnInstance>) yaml.load(output1);
+ assertEquals(value, value2);
+ } catch (ConstructorException e) {
+ // TODO recursive objects are not allowed
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testList() {
+ List value = new ArrayList();
+ value.add(value);
+ Yaml yaml = new Yaml();
+ try {
+ String output1 = yaml.dump(value);
+ System.out.println(output1);
+ List value2 = (List) yaml.load(output1);
+ assertEquals(value, value2);
+ } catch (ConstructorException e) {
+ // TODO recursive objects are not allowed
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testSet() {
+ Set value = new HashSet();
+ value.add(new AnInstance(value, value));
+ Yaml yaml = new Yaml();
+ try {
+ String output1 = yaml.dump(value);
+ List value2 = (List) yaml.load(output1);
+ assertEquals(value, value2);
+ } catch (ConstructorException e) {
+ // TODO recursive objects are not allowed
+ }
+ }
+}
diff --git a/src/test/java/org/pyyaml/PyStructureTest.java b/src/test/java/org/pyyaml/PyStructureTest.java new file mode 100644 index 00000000..0362ee5c --- /dev/null +++ b/src/test/java/org/pyyaml/PyStructureTest.java @@ -0,0 +1,287 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.pyyaml;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.yaml.snakeyaml.Loader;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.composer.Composer;
+import org.yaml.snakeyaml.constructor.Construct;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.events.AliasEvent;
+import org.yaml.snakeyaml.events.CollectionStartEvent;
+import org.yaml.snakeyaml.events.Event;
+import org.yaml.snakeyaml.events.ScalarEvent;
+import org.yaml.snakeyaml.nodes.MappingNode;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.ScalarNode;
+import org.yaml.snakeyaml.nodes.SequenceNode;
+import org.yaml.snakeyaml.parser.ParserImpl;
+import org.yaml.snakeyaml.reader.Reader;
+import org.yaml.snakeyaml.reader.UnicodeReader;
+import org.yaml.snakeyaml.resolver.Resolver;
+
+/**
+ * @see imported from PyYAML
+ */
+public class PyStructureTest extends PyImportTest {
+
+ private void compareEvents(List<Event> events1, List<Event> events2, boolean full) {
+ assertEquals(events1.size(), events2.size());
+ Iterator<Event> iter1 = events1.iterator();
+ Iterator<Event> iter2 = events2.iterator();
+ while (iter1.hasNext()) {
+ Event event1 = iter1.next();
+ Event event2 = iter2.next();
+ assertEquals(event1.getClass(), event2.getClass());
+ if (event1 instanceof AliasEvent && full) {
+ assertEquals(((AliasEvent) event1).getAnchor(), ((AliasEvent) event2).getAnchor());
+ }
+ if (event1 instanceof CollectionStartEvent) {
+ String tag1 = ((CollectionStartEvent) event1).getTag();
+ String tag2 = ((CollectionStartEvent) event1).getTag();
+ if (tag1 != null && !"!".equals(tag1) && tag2 != null && !"!".equals(tag1)) {
+ assertEquals(tag1, tag2);
+ }
+ }
+ if (event1 instanceof ScalarEvent) {
+ ScalarEvent scalar1 = (ScalarEvent) event1;
+ ScalarEvent scalar2 = (ScalarEvent) event2;
+ boolean[] oldImplicit = scalar1.getImplicit();
+ boolean[] newImplicit = scalar2.getImplicit();
+ if (!oldImplicit[0] && !oldImplicit[1] && !newImplicit[0] && !newImplicit[1]) {
+ assertEquals(scalar1.getTag(), scalar2.getTag());
+ }
+ assertEquals(scalar1.getValue(), scalar2.getValue());
+ }
+ }
+ }
+
+ public void testParser() throws IOException {
+ File[] files = getStreamsByExtension(".data", true);
+ assertTrue("No test files found.", files.length > 0);
+ for (File file : files) {
+ if (!file.getName().contains("scan-line-b")) {
+ continue;
+ }
+ try {
+ List<Event> events1 = parse(new FileInputStream(file));
+ assertFalse(events1.isEmpty());
+ int index = file.getAbsolutePath().lastIndexOf('.');
+ String canonicalName = file.getAbsolutePath().substring(0, index) + ".canonical";
+ File canonical = new File(canonicalName);
+ List<Event> events2 = canonicalParse(new FileInputStream(canonical));
+ assertFalse(events2.isEmpty());
+ System.out.println("try:" + file);
+ compareEvents(events1, events2, false);
+ } catch (Exception e) {
+ System.out.println("Failed File: " + file);
+ // fail("Failed File: " + file + "; " + e.getMessage());
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ public void testParserOnCanonical() throws IOException {
+ File[] canonicalFiles = getStreamsByExtension(".canonical", false);
+ assertTrue("No test files found.", canonicalFiles.length > 0);
+ for (File file : canonicalFiles) {
+ try {
+ List<Event> events1 = parse(new FileInputStream(file));
+ assertFalse(events1.isEmpty());
+ List<Event> events2 = canonicalParse(new FileInputStream(file));
+ assertFalse(events2.isEmpty());
+ compareEvents(events1, events2, true);
+ } catch (Exception e) {
+ System.out.println("Failed File: " + file);
+ // fail("Failed File: " + file + "; " + e.getMessage());
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ private void compareNodes(Node node1, Node node2) {
+ assertEquals(node1.getClass(), node2.getClass());
+ if (node1 instanceof ScalarNode) {
+ ScalarNode scalar1 = (ScalarNode) node1;
+ ScalarNode scalar2 = (ScalarNode) node2;
+ assertEquals(scalar1.getTag(), scalar2.getTag());
+ assertEquals(scalar1.getValue(), scalar2.getValue());
+ } else {
+ if (node1 instanceof SequenceNode) {
+ SequenceNode seq1 = (SequenceNode) node1;
+ SequenceNode seq2 = (SequenceNode) node2;
+ assertEquals(seq1.getTag(), seq2.getTag());
+ assertEquals(seq1.getValue().size(), seq2.getValue().size());
+ Iterator<Node> iter2 = seq2.getValue().iterator();
+ for (Node child1 : seq1.getValue()) {
+ Node child2 = iter2.next();
+ compareNodes(child1, child2);
+ }
+ } else {
+ MappingNode seq1 = (MappingNode) node1;
+ MappingNode seq2 = (MappingNode) node2;
+ assertEquals(seq1.getTag(), seq2.getTag());
+ assertEquals(seq1.getValue().size(), seq2.getValue().size());
+ Iterator<Node[]> iter2 = seq2.getValue().iterator();
+ for (Node[] child1 : seq1.getValue()) {
+ Node[] child2 = iter2.next();
+ compareNodes(child1[0], child2[0]);// keys
+ compareNodes(child1[1], child2[1]);// values
+ }
+ }
+ }
+ }
+
+ public void testComposer() throws IOException {
+ File[] files = getStreamsByExtension(".data", true);
+ assertTrue("No test files found.", files.length > 0);
+ for (File file : files) {
+ try {
+ List<Node> events1 = compose_all(new FileInputStream(file));
+ int index = file.getAbsolutePath().lastIndexOf('.');
+ String canonicalName = file.getAbsolutePath().substring(0, index) + ".canonical";
+ File canonical = new File(canonicalName);
+ List<Node> events2 = canonical_compose_all(new FileInputStream(canonical));
+ assertEquals(events1.size(), events2.size());
+ Iterator<Node> iter1 = events1.iterator();
+ Iterator<Node> iter2 = events2.iterator();
+ while (iter1.hasNext()) {
+ compareNodes(iter1.next(), iter2.next());
+ }
+ } catch (Exception e) {
+ System.out.println("Failed File: " + file);
+ // fail("Failed File: " + file + "; " + e.getMessage());
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ private List<Node> compose_all(InputStream file) {
+ Composer composer = new Composer(new ParserImpl(new Reader(new UnicodeReader(file))),
+ new Resolver());
+ List<Node> documents = new LinkedList<Node>();
+ while (composer.checkNode()) {
+ documents.add(composer.getNode());
+ }
+ return documents;
+ }
+
+ private List<Node> canonical_compose_all(InputStream file) {
+ Reader reader = new Reader(new UnicodeReader(file));
+ StringBuffer buffer = new StringBuffer();
+ while (reader.peek() != '\0') {
+ buffer.append(reader.peek());
+ reader.forward();
+ }
+ CanonicalParser parser = new CanonicalParser(buffer.toString());
+ Composer composer = new Composer(parser, new Resolver());
+ List<Node> documents = new LinkedList<Node>();
+ while (composer.checkNode()) {
+ documents.add(composer.getNode());
+ }
+ return documents;
+ }
+
+ class MyLoader extends Loader {
+ public MyLoader() {
+ super(new MyConstructor());
+ }
+ }
+
+ class CanonicalLoader extends Loader {
+ public CanonicalLoader() {
+ super(new MyConstructor());
+ }
+
+ @Override
+ public Iterable<Object> loadAll(java.io.Reader yaml) {
+ Reader reader = new Reader(yaml);
+ StringBuffer buffer = new StringBuffer();
+ while (reader.peek() != '\0') {
+ buffer.append(reader.peek());
+ reader.forward();
+ }
+ CanonicalParser parser = new CanonicalParser(buffer.toString());
+ Composer composer = new Composer(parser, resolver);
+ this.constructor.setComposer(composer);
+ Iterator<Object> result = new Iterator<Object>() {
+ public boolean hasNext() {
+ return constructor.checkData();
+ }
+
+ public Object next() {
+ return constructor.getData();
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ return new YamlIterable(result);
+ }
+
+ private class YamlIterable implements Iterable<Object> {
+ private Iterator<Object> iterator;
+
+ public YamlIterable(Iterator<Object> iterator) {
+ this.iterator = iterator;
+ }
+
+ public Iterator<Object> iterator() {
+ return iterator;
+ }
+
+ }
+
+ }
+
+ private class MyConstructor extends Constructor {
+ public MyConstructor() {
+ this.yamlConstructors.put(null, new ConstructUndefined());
+ }
+
+ private class ConstructUndefined implements Construct {
+ public Object construct(Node node) {
+ return constructScalar((ScalarNode) node);
+ }
+ }
+ }
+
+ public void testConstructor() throws IOException {
+ File[] files = getStreamsByExtension(".data", true);
+ assertTrue("No test files found.", files.length > 0);
+ Yaml myYaml = new Yaml(new MyLoader());
+ Yaml canonicalYaml = new Yaml(new CanonicalLoader());
+ for (File file : files) {
+ try {
+ Iterable<Object> documents1 = myYaml.loadAll(new FileInputStream(file));
+ int index = file.getAbsolutePath().lastIndexOf('.');
+ String canonicalName = file.getAbsolutePath().substring(0, index) + ".canonical";
+ File canonical = new File(canonicalName);
+ Iterable<Object> documents2 = canonicalYaml.loadAll(new FileInputStream(canonical));
+ Iterator<Object> iter2 = documents2.iterator();
+ for (Object object1 : documents1) {
+ Object object2 = iter2.next();
+ if (object2 != null) {
+ assertFalse(System.identityHashCode(object1) == System
+ .identityHashCode(object2));
+ }
+ assertEquals("" + object1, object1, object2);
+ }
+ } catch (Exception e) {
+ System.out.println("Failed File: " + file);
+ // fail("Failed File: " + file + "; " + e.getMessage());
+ throw new RuntimeException(e);
+ }
+ }
+ }
+}
diff --git a/src/test/java/org/pyyaml/PyTokensTest.java b/src/test/java/org/pyyaml/PyTokensTest.java new file mode 100644 index 00000000..42f65948 --- /dev/null +++ b/src/test/java/org/pyyaml/PyTokensTest.java @@ -0,0 +1,140 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.pyyaml;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.yaml.snakeyaml.reader.Reader;
+import org.yaml.snakeyaml.reader.UnicodeReader;
+import org.yaml.snakeyaml.scanner.Scanner;
+import org.yaml.snakeyaml.scanner.ScannerImpl;
+import org.yaml.snakeyaml.tokens.AliasToken;
+import org.yaml.snakeyaml.tokens.AnchorToken;
+import org.yaml.snakeyaml.tokens.BlockEndToken;
+import org.yaml.snakeyaml.tokens.BlockEntryToken;
+import org.yaml.snakeyaml.tokens.BlockMappingStartToken;
+import org.yaml.snakeyaml.tokens.BlockSequenceStartToken;
+import org.yaml.snakeyaml.tokens.DirectiveToken;
+import org.yaml.snakeyaml.tokens.DocumentEndToken;
+import org.yaml.snakeyaml.tokens.DocumentStartToken;
+import org.yaml.snakeyaml.tokens.FlowEntryToken;
+import org.yaml.snakeyaml.tokens.FlowMappingEndToken;
+import org.yaml.snakeyaml.tokens.FlowMappingStartToken;
+import org.yaml.snakeyaml.tokens.FlowSequenceEndToken;
+import org.yaml.snakeyaml.tokens.FlowSequenceStartToken;
+import org.yaml.snakeyaml.tokens.KeyToken;
+import org.yaml.snakeyaml.tokens.ScalarToken;
+import org.yaml.snakeyaml.tokens.StreamEndToken;
+import org.yaml.snakeyaml.tokens.StreamStartToken;
+import org.yaml.snakeyaml.tokens.TagToken;
+import org.yaml.snakeyaml.tokens.Token;
+import org.yaml.snakeyaml.tokens.ValueToken;
+
+/**
+ * @see imported from PyYAML
+ */
+public class PyTokensTest extends PyImportTest {
+
+ @SuppressWarnings("unchecked")
+ public void testTokens() throws FileNotFoundException {
+ Map<Class, String> replaces = new HashMap<Class, String>();
+ replaces.put(DirectiveToken.class, "%");
+ replaces.put(DocumentStartToken.class, "---");
+ replaces.put(DocumentEndToken.class, "...");
+ replaces.put(AliasToken.class, "*");
+ replaces.put(AnchorToken.class, "&");
+ replaces.put(TagToken.class, "!");
+ replaces.put(ScalarToken.class, "_");
+ replaces.put(BlockSequenceStartToken.class, "[[");
+ replaces.put(BlockMappingStartToken.class, "{{");
+ replaces.put(BlockEndToken.class, "]}");
+ replaces.put(FlowSequenceStartToken.class, "[");
+ replaces.put(FlowSequenceEndToken.class, "]");
+ replaces.put(FlowMappingStartToken.class, "{");
+ replaces.put(FlowMappingEndToken.class, "}");
+ replaces.put(BlockEntryToken.class, ",");
+ replaces.put(FlowEntryToken.class, ",");
+ replaces.put(KeyToken.class, "?");
+ replaces.put(ValueToken.class, ":");
+ //
+ File[] tokensFiles = getStreamsByExtension(".tokens");
+ assertTrue("No test files found.", tokensFiles.length > 0);
+ for (int i = 0; i < tokensFiles.length; i++) {
+ String name = tokensFiles[i].getName();
+ int position = name.lastIndexOf('.');
+ String dataName = name.substring(0, position) + ".data";
+ //
+ String tokenFileData = getResource(name);
+ String[] split = tokenFileData.split("\\s+");
+ List<String> tokens2 = new LinkedList<String>();
+ for (int j = 0; j < split.length; j++) {
+ tokens2.add(split[j]);
+ }
+ //
+ List<String> tokens1 = new LinkedList<String>();
+ Reader reader = new Reader(new UnicodeReader(new FileInputStream(
+ getFileByName(dataName))));
+ Scanner scanner = new ScannerImpl(reader);
+ try {
+ while (scanner.checkToken(new ArrayList<Class<? extends Token>>())) {
+ Token token = scanner.getToken();
+ if (!(token instanceof StreamStartToken || token instanceof StreamEndToken)) {
+ String replacement = replaces.get(token.getClass());
+ tokens1.add(replacement);
+ }
+ }
+ // System.out.println("File name: \n" +
+ // tokensFiles[i].getName());
+ // Iterator iter = tokens2.iterator();
+ // for (String string : tokens1) {
+ // String str2 = (String) iter.next();
+ // System.out.println(string + "=" + str2);
+ // }
+ assertEquals(tokenFileData, tokens1.size(), tokens2.size());
+ assertEquals(tokens1, tokens2);
+ } catch (RuntimeException e) {
+ System.out.println("File name: \n" + tokensFiles[i].getName());
+ String data = getResource(tokensFiles[i].getName());
+ System.out.println("Data: \n" + data);
+ System.out.println("Tokens:");
+ for (String token : tokens1) {
+ System.out.println(token);
+ }
+ fail("Cannot scan: " + tokensFiles[i]);
+ }
+ }
+ }
+
+ public void testScanner() throws FileNotFoundException {
+ File[] files = getStreamsByExtension(".data", true);
+ assertTrue("No test files found.", files.length > 0);
+ for (File file : files) {
+ List<String> tokens = new LinkedList<String>();
+ Reader reader = new Reader(new UnicodeReader(new FileInputStream(file)));
+ Scanner scanner = new ScannerImpl(reader);
+ try {
+ while (scanner.checkToken(new ArrayList<Class<? extends Token>>())) {
+ Token token = scanner.getToken();
+ tokens.add(token.getClass().getName());
+ }
+ } catch (RuntimeException e) {
+ System.out.println("File name: \n" + file.getName());
+ String data = getResource(file.getName());
+ System.out.println("Data: \n" + data);
+ System.out.println("Tokens:");
+ for (String token : tokens) {
+ System.out.println(token);
+ }
+ fail("Cannot scan: " + file + "; " + e.getMessage());
+ }
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/Address.java b/src/test/java/org/yaml/snakeyaml/Address.java new file mode 100644 index 00000000..e18fb5d0 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/Address.java @@ -0,0 +1,11 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml;
+
+public class Address {
+ public String lines;
+ public String city;
+ public String state;
+ public String postal;
+}
\ No newline at end of file diff --git a/src/test/java/org/yaml/snakeyaml/BinaryBean.java b/src/test/java/org/yaml/snakeyaml/BinaryBean.java new file mode 100644 index 00000000..026b1519 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/BinaryBean.java @@ -0,0 +1,26 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml;
+
+public class BinaryBean {
+ byte[] data;
+ int id;
+
+ public byte[] getData() {
+ return data;
+ }
+
+ public void setData(byte[] data) {
+ this.data = data;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+}
\ No newline at end of file diff --git a/src/test/java/org/yaml/snakeyaml/BinaryJavaBeanTest.java b/src/test/java/org/yaml/snakeyaml/BinaryJavaBeanTest.java new file mode 100644 index 00000000..7121c375 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/BinaryJavaBeanTest.java @@ -0,0 +1,20 @@ +package org.yaml.snakeyaml;
+
+import junit.framework.TestCase;
+
+public class BinaryJavaBeanTest extends TestCase {
+ public void testBeanTest() {
+ BinaryBean bean = new BinaryBean();
+ bean.setId(1);
+ byte[] bytes = new byte[] { 1, 7, 9, 31, 65 };
+ bean.setData(bytes);
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(bean);
+ String etalon = "!!org.yaml.snakeyaml.BinaryBean\ndata: !!binary |-\n AQcJH0E=\nid: 1\n";
+ assertEquals(etalon, output);
+ // load
+ BinaryBean bean2 = (BinaryBean) yaml.load(output);
+ assertEquals(1, bean2.getId());
+ assertEquals(new String(bytes), new String(bean2.getData()));
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/Chapter2_1Test.java b/src/test/java/org/yaml/snakeyaml/Chapter2_1Test.java new file mode 100644 index 00000000..c66dfe0e --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/Chapter2_1Test.java @@ -0,0 +1,96 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml;
+
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+/**
+ * Test Chapter 2.1 from the YAML specification
+ *
+ * @author py4fun
+ * @see http://yaml.org/spec/1.1/
+ */
+public class Chapter2_1Test extends TestCase {
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_1() {
+ YamlDocument document = new YamlDocument("example2_1.yaml");
+ List<String> list = (List<String>) document.getNativeData();
+ assertEquals(3, list.size());
+ assertEquals("Mark McGwire", list.get(0));
+ assertEquals("Sammy Sosa", list.get(1));
+ assertEquals("Ken Griffey", list.get(2));
+ assertEquals("[Mark McGwire, Sammy Sosa, Ken Griffey]\n", document.getPresentation());
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_2() {
+ YamlDocument document = new YamlDocument("example2_2.yaml");
+ Map<String, Object> map = (Map<String, Object>) document.getNativeData();
+ assertEquals(3, map.size());
+ assertEquals("Expect 65 to be a Integer", Integer.class, map.get("hr").getClass());
+ assertEquals(new Integer(65), map.get("hr"));
+ assertEquals(new Float(0.278), new Float("0.278"));
+ assertEquals("Expect 0.278 to be a Float", Double.class, map.get("avg").getClass());
+ assertEquals(new Double(0.278), map.get("avg"));
+ assertEquals("Expect 147 to be an Integer", Integer.class, map.get("rbi").getClass());
+ assertEquals(new Integer(147), map.get("rbi"));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_3() {
+ YamlDocument document = new YamlDocument("example2_3.yaml");
+ Map<String, List<String>> map = (Map<String, List<String>>) document.getNativeData();
+ assertEquals(2, map.size());
+ List<String> list1 = map.get("american");
+ assertEquals(3, list1.size());
+ assertEquals("Boston Red Sox", list1.get(0));
+ assertEquals("Detroit Tigers", list1.get(1));
+ assertEquals("New York Yankees", list1.get(2));
+ List<String> list2 = map.get("national");
+ assertEquals(3, list2.size());
+ assertEquals("New York Mets", list2.get(0));
+ assertEquals("Chicago Cubs", list2.get(1));
+ assertEquals("Atlanta Braves", list2.get(2));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_4() {
+ YamlDocument document = new YamlDocument("example2_4.yaml");
+ List<Map<String, Object>> list = (List<Map<String, Object>>) document.getNativeData();
+ assertEquals(2, list.size());
+ Map<String, Object> map1 = list.get(0);
+ assertEquals(3, map1.size());
+ assertEquals("Mark McGwire", map1.get("name"));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_5() {
+ YamlDocument document = new YamlDocument("example2_5.yaml");
+ List<List<Object>> list = (List<List<Object>>) document.getNativeData();
+ assertEquals(3, list.size());
+ List<Object> list1 = list.get(0);
+ assertEquals(3, list1.size());
+ assertEquals("name", list1.get(0));
+ assertEquals("hr", list1.get(1));
+ assertEquals("avg", list1.get(2));
+ assertEquals(3, list.get(1).size());
+ assertEquals(3, list.get(2).size());
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_6() {
+ YamlDocument document = new YamlDocument("example2_6.yaml");
+ Map<String, Map<String, Object>> map = (Map<String, Map<String, Object>>) document
+ .getNativeData();
+ assertEquals(2, map.size());
+ Map<String, Object> map1 = map.get("Mark McGwire");
+ assertEquals(2, map1.size());
+ Map<String, Object> map2 = map.get("Sammy Sosa");
+ assertEquals(2, map2.size());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/Chapter2_2Test.java b/src/test/java/org/yaml/snakeyaml/Chapter2_2Test.java new file mode 100644 index 00000000..1e166ee7 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/Chapter2_2Test.java @@ -0,0 +1,101 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml;
+
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+/**
+ * Test Chapter 2.2 from the YAML specification
+ *
+ * @author py4fun
+ * @see http://yaml.org/spec/1.1/
+ */
+public class Chapter2_2Test extends TestCase {
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_7() {
+ YamlStream resource = new YamlStream("example2_7.yaml");
+ List<Object> list = (List<Object>) resource.getNativeData();
+ assertEquals(2, list.size());
+ List<String> list1 = (List<String>) list.get(0);
+ assertEquals(3, list1.size());
+ assertEquals("Mark McGwire", list1.get(0));
+ assertEquals("Sammy Sosa", list1.get(1));
+ assertEquals("Ken Griffey", list1.get(2));
+ List<String> list2 = (List<String>) list.get(1);
+ assertEquals(2, list2.size());
+ assertEquals("Chicago Cubs", list2.get(0));
+ assertEquals("St Louis Cardinals", list2.get(1));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_8() {
+ YamlStream resource = new YamlStream("example2_8.yaml");
+ List<Object> list = (List<Object>) resource.getNativeData();
+ assertEquals(2, list.size());
+ Map<String, String> map1 = (Map<String, String>) list.get(0);
+ assertEquals(3, map1.size());
+ assertEquals(new Integer(72200), map1.get("time"));
+ assertEquals("Sammy Sosa", map1.get("player"));
+ assertEquals("strike (miss)", map1.get("action"));
+ Map<String, String> map2 = (Map<String, String>) list.get(1);
+ assertEquals(3, map2.size());
+ assertEquals(new Integer(72227), map2.get("time"));
+ assertEquals("Sammy Sosa", map2.get("player"));
+ assertEquals("grand slam", map2.get("action"));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_9() {
+ YamlDocument document = new YamlDocument("example2_9.yaml");
+ Map<String, Object> map = (Map<String, Object>) document.getNativeData();
+ assertEquals(map.toString(), 2, map.size());
+ List<String> list1 = (List<String>) map.get("hr");
+ assertEquals(2, list1.size());
+ assertEquals("Mark McGwire", list1.get(0));
+ assertEquals("Sammy Sosa", list1.get(1));
+ List<String> list2 = (List<String>) map.get("rbi");
+ assertEquals(2, list2.size());
+ assertEquals("Sammy Sosa", list2.get(0));
+ assertEquals("Ken Griffey", list2.get(1));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_10() {
+ YamlDocument document = new YamlDocument("example2_10.yaml");
+ Map<String, Object> map = (Map<String, Object>) document.getNativeData();
+ assertEquals("Examples 2.9 and 2.10 must be identical.",
+ new YamlDocument("example2_9.yaml").getNativeData(), map);
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_11() {
+ YamlDocument document = new YamlDocument("example2_11.yaml");
+ Map<Object, Object> map = (Map<Object, Object>) document.getNativeData();
+ assertEquals(2, map.size());
+ for (Object key : map.keySet()) {
+ List<String> list = (List<String>) key;
+ assertEquals(2, list.size());
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_12() {
+ YamlDocument document = new YamlDocument("example2_12.yaml");
+ List<Map<Object, Object>> list = (List<Map<Object, Object>>) document.getNativeData();
+ assertEquals(3, list.size());
+ Map map1 = (Map) list.get(0);
+ assertEquals(2, map1.size());
+ assertEquals("Super Hoop", map1.get("item"));
+ Map map2 = (Map) list.get(1);
+ assertEquals(2, map2.size());
+ assertEquals("Basketball", map2.get("item"));
+ Map map3 = (Map) list.get(2);
+ assertEquals(2, map3.size());
+ assertEquals("Big Shoes", map3.get("item"));
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/Chapter2_3Test.java b/src/test/java/org/yaml/snakeyaml/Chapter2_3Test.java new file mode 100644 index 00000000..74d9b537 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/Chapter2_3Test.java @@ -0,0 +1,120 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+/**
+ * Test Chapter 2.3 from the YAML specification
+ *
+ * @author py4fun
+ * @see http://yaml.org/spec/1.1/
+ */
+public class Chapter2_3Test extends TestCase {
+
+ public void testExample_2_13() {
+ YamlDocument document = new YamlDocument("example2_13.yaml");
+ String data = (String) document.getNativeData();
+ assertEquals("\\//||\\/||\n// || ||__\n", data);
+ }
+
+ public void testExample_2_14() {
+ YamlDocument document = new YamlDocument("example2_14.yaml");
+ String data = (String) document.getNativeData();
+ assertEquals("Mark McGwire's year was crippled by a knee injury.", data);
+ }
+
+ public void testExample_2_15() {
+ String etalon = "Sammy Sosa completed another fine season with great stats.\n\n 63 Home Runs\n 0.288 Batting Average\n\nWhat a year!\n";
+ InputStream input = YamlDocument.class.getClassLoader().getResourceAsStream(
+ YamlDocument.ROOT + "example2_15.yaml");
+ Yaml yaml = new Yaml();
+ String data = (String) yaml.load(input);
+ assertEquals(etalon, data);
+ //
+ String dumped = yaml.dump(data);
+ assertTrue(dumped.contains("Sammy Sosa completed another fine season with great stats"));
+ assertEquals("Must be splitted into 2 lines.", 2, dumped.split("\n").length);
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_16() {
+ YamlDocument document = new YamlDocument("example2_16.yaml");
+ Map<String, String> map = (Map<String, String>) document.getNativeData();
+ assertEquals(map.toString(), 3, map.size());
+ assertEquals("Mark McGwire", map.get("name"));
+ assertEquals("Mark set a major league home run record in 1998.\n", map
+ .get("accomplishment"));
+ assertEquals("65 Home Runs\n0.278 Batting Average\n", map.get("stats"));
+
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_17() throws IOException {
+ YamlDocument document = new YamlDocument("example2_17.yaml", false);
+ Map<String, String> map = (Map<String, String>) document.getNativeData();
+ assertEquals(map.toString(), 6, map.size());
+ assertEquals("Sosa did fine.\u263A", map.get("unicode"));
+ assertEquals("\b1998\t1999\t2000\n", map.get("control"));
+ assertEquals("\r\n is \r\n", map.get("hexesc"));
+ assertEquals("\"Howdy!\" he cried.", map.get("single"));
+ assertEquals(" # not a 'comment'.", map.get("quoted"));
+ assertEquals("|\\-*-/|", map.get("tie-fighter"));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_17_unicode() {
+ YamlDocument document = new YamlDocument("example2_17_unicode.yaml");
+ Map<String, String> map = (Map<String, String>) document.getNativeData();
+ assertEquals("Sosa did fine.\u263A", map.get("unicode"));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_17_control() {
+ YamlDocument document = new YamlDocument("example2_17_control.yaml", false);
+ Map<String, String> map = (Map<String, String>) document.getNativeData();
+ assertEquals("\b1998\t1999\t2000\n", map.get("control"));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_17_hexesc() {
+ YamlDocument document = new YamlDocument("example2_17_hexesc.yaml");
+ Map<String, String> map = (Map<String, String>) document.getNativeData();
+ assertEquals("\r\n is \r\n", map.get("hexesc"));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_17_single() {
+ YamlDocument document = new YamlDocument("example2_17_single.yaml");
+ Map<String, String> map = (Map<String, String>) document.getNativeData();
+ assertEquals("\"Howdy!\" he cried.", map.get("single"));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_17_quoted() {
+ YamlDocument document = new YamlDocument("example2_17_quoted.yaml");
+ Map<String, String> map = (Map<String, String>) document.getNativeData();
+ assertEquals(" # not a 'comment'.", map.get("quoted"));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_17_tie_fighter() {
+ YamlDocument document = new YamlDocument("example2_17_tie_fighter.yaml");
+ Map<String, String> map = (Map<String, String>) document.getNativeData();
+ assertEquals("|\\-*-/|", map.get("tie-fighter"));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_18() throws IOException {
+ YamlDocument document = new YamlDocument("example2_18.yaml");
+ Map<String, String> map = (Map<String, String>) document.getNativeData();
+ assertEquals(map.toString(), 2, map.size());
+ assertEquals("This unquoted scalar spans many lines.", map.get("plain"));
+ assertEquals("So does this quoted scalar.\n", map.get("quoted"));
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/Chapter2_4Test.java b/src/test/java/org/yaml/snakeyaml/Chapter2_4Test.java new file mode 100644 index 00000000..2a2ce53c --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/Chapter2_4Test.java @@ -0,0 +1,171 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TimeZone;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.constructor.Construct;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.ScalarNode;
+
+/**
+ * Test Chapter 2.4 from the YAML specification
+ *
+ * @author py4fun
+ * @see http://yaml.org/spec/1.1/
+ */
+public class Chapter2_4Test extends TestCase {
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_19() {
+ YamlDocument document = new YamlDocument("example2_19.yaml");
+ Map<String, Object> map = (Map<String, Object>) document.getNativeData();
+ assertEquals(5, map.size());
+ assertEquals("Expect 12345 to be an Integer.", Integer.class, map.get("canonical")
+ .getClass());
+ assertEquals(new Integer(12345), map.get("canonical"));
+ assertEquals(new Integer(12345), map.get("decimal"));
+ assertEquals(new Integer(3 * 3600 + 25 * 60 + 45), map.get("sexagesimal"));
+ assertEquals(new Integer(014), map.get("octal"));
+ assertEquals(new Integer(0xC), map.get("hexadecimal"));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_20() {
+ YamlDocument document = new YamlDocument("example2_20.yaml");
+ Map<String, Object> map = (Map<String, Object>) document.getNativeData();
+ assertEquals(6, map.size());
+ assertEquals("Expect '1.23015e+3' to be a Double.", Double.class, map.get("canonical")
+ .getClass());
+ assertEquals(new Double(1230.15), map.get("canonical"));
+ assertEquals(new Double(12.3015e+02), map.get("exponential"));
+ assertEquals(new Double(20 * 60 + 30.15), map.get("sexagesimal"));
+ assertEquals(new Double(1230.15), map.get("fixed"));
+ assertEquals(Double.NEGATIVE_INFINITY, map.get("negative infinity"));
+ assertEquals(Double.NaN, map.get("not a number"));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_21() {
+ YamlDocument document = new YamlDocument("example2_21.yaml");
+ Map<String, Object> map = (Map<String, Object>) document.getNativeData();
+ assertEquals(4, map.size());
+ assertNull("'~' must be parsed as 'null': " + map.get(null), map.get(null));
+ assertTrue((Boolean) map.get(Boolean.TRUE));
+ assertFalse((Boolean) map.get(Boolean.FALSE));
+ assertEquals("12345", map.get("string"));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_22() {
+ YamlDocument document = new YamlDocument("example2_22.yaml");
+ Map<String, Object> map = (Map<String, Object>) document.getNativeData();
+ assertEquals(4, map.size());
+ assertEquals("Expect '2001-12-15T02:59:43.1Z' to be a Date.", Date.class, map.get(
+ "canonical").getClass());
+ Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
+ cal.clear();
+ cal.set(Calendar.YEAR, 2001);
+ cal.set(Calendar.MONTH, 11); // Java's months are zero-based...
+ cal.set(Calendar.DAY_OF_MONTH, 15);
+ cal.set(Calendar.HOUR_OF_DAY, 2);
+ cal.set(Calendar.MINUTE, 59);
+ cal.set(Calendar.SECOND, 43);
+ cal.set(Calendar.MILLISECOND, 100);
+ Date date = cal.getTime();
+ assertEquals(date, map.get("canonical"));
+ assertEquals("Expect '2001-12-14t21:59:43.10-05:00' to be a Date.", Date.class, map.get(
+ "iso8601").getClass());
+ assertEquals("Expect '2001-12-14 21:59:43.10 -5' to be a Date.", Date.class, map.get(
+ "spaced").getClass());
+ assertEquals("Expect '2002-12-14' to be a Date.", Date.class, map.get("date").getClass());
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_23_non_date() {
+ try {
+ YamlDocument document = new YamlDocument("example2_23_non_date.yaml");
+ Map<String, Object> map = (Map<String, Object>) document.getNativeData();
+ assertEquals(1, map.size());
+ assertEquals("2002-04-28", map.get("not-date"));
+ } catch (RuntimeException e) {
+ fail("Cannot parse '!!str': 'not-date: !!str 2002-04-28'");
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_23_picture() throws Exception {
+ YamlDocument document = new YamlDocument("example2_23_picture.yaml", false);
+ Map<String, Object> map = (Map<String, Object>) document.getNativeData();
+ assertEquals(1, map.size());
+ byte[] picture = (byte[]) map.get("picture");
+ assertEquals((byte) 'G', picture[0]);
+ assertEquals((byte) 'I', picture[1]);
+ assertEquals((byte) 'F', picture[2]);
+ }
+
+ class SomethingConstructor extends Constructor {
+ public SomethingConstructor() {
+ this.yamlConstructors.put("!something", new ConstructSomething());
+ }
+
+ private class ConstructSomething implements Construct {
+ public Object construct(Node node) {
+ // convert to upper case
+ String val = (String) constructScalar((ScalarNode) node);
+ return val.toUpperCase().replace('\n', ' ').trim();
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_23() throws IOException {
+ YamlDocument document = new YamlDocument("example2_23.yaml", false,
+ new SomethingConstructor());
+ Map<String, Object> map = (Map<String, Object>) document.getNativeData();
+ assertEquals(3, map.size());
+ String special = (String) map.get("application specific tag");
+ assertEquals("THE SEMANTICS OF THE TAG ABOVE MAY BE DIFFERENT FOR DIFFERENT DOCUMENTS.",
+ special);
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_25() {
+ YamlDocument document = new YamlDocument("example2_25.yaml");
+ Set<String> set = (Set<String>) document.getNativeData();
+ assertEquals(3, set.size());
+ assertTrue(set.contains("Mark McGwire"));
+ assertTrue(set.contains("Sammy Sosa"));
+ assertTrue(set.contains("Ken Griff"));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_26() {
+ YamlDocument document = new YamlDocument("example2_26.yaml");
+ Map<String, String> map = (Map<String, String>) document.getNativeData();
+ assertEquals(3, map.size());
+ assertTrue(map instanceof LinkedHashMap);
+ assertEquals(new Integer(65), map.get("Mark McGwire"));
+ assertEquals(new Integer(63), map.get("Sammy Sosa"));
+ assertEquals(new Integer(58), map.get("Ken Griffy"));
+ List list = new ArrayList();
+ for (String key : map.keySet()) {
+ list.add(key);
+ }
+ assertEquals("Mark McGwire", list.get(0));
+ assertEquals("Sammy Sosa", list.get(1));
+ assertEquals("Ken Griffy", list.get(2));
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/Chapter2_5Test.java b/src/test/java/org/yaml/snakeyaml/Chapter2_5Test.java new file mode 100644 index 00000000..d80890ff --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/Chapter2_5Test.java @@ -0,0 +1,52 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml;
+
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+/**
+ * Test Chapter 2.5 from the YAML specification
+ *
+ * @author py4fun
+ * @see http://yaml.org/spec/1.1/
+ */
+public class Chapter2_5Test extends TestCase {
+
+ @SuppressWarnings("unchecked")
+ public void testExample_2_28() {
+ YamlStream resource = new YamlStream("example2_28.yaml");
+ List<Object> list = (List<Object>) resource.getNativeData();
+ assertEquals(3, list.size());
+ Map<String, Object> data0 = (Map<String, Object>) list.get(0);
+ Date date = (Date) data0.get("Time");
+ assertEquals("Date: " + date, 1006545702000L, date.getTime());
+ assertEquals("ed", data0.get("User"));
+ assertEquals("This is an error message for the log file", data0.get("Warning"));
+ //
+ Map<String, Object> data1 = (Map<String, Object>) list.get(1);
+ Date date1 = (Date) data1.get("Time");
+ assertTrue("Date: " + date1, date1.after(date));
+ assertEquals("ed", data1.get("User"));
+ assertEquals("A slightly different error message.", data1.get("Warning"));
+ //
+ Map<String, Object> data3 = (Map<String, Object>) list.get(2);
+ Date date3 = (Date) data3.get("Date");
+ assertTrue("Date: " + date3, date3.after(date1));
+ assertEquals("ed", data3.get("User"));
+ assertEquals("Unknown variable \"bar\"", data3.get("Fatal"));
+ List<Map<String, String>> list3 = (List<Map<String, String>>) data3.get("Stack");
+ Map<String, String> map1 = list3.get(0);
+ assertEquals("TopClass.py", map1.get("file"));
+ assertEquals(new Integer(23), map1.get("line"));
+ assertEquals("x = MoreObject(\"345\\n\")\n", map1.get("code"));
+ Map<String, String> map2 = list3.get(1);
+ assertEquals("MoreClass.py", map2.get("file"));
+ assertEquals(new Integer(58), map2.get("line"));
+ assertEquals("foo = bar", map2.get("code"));
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/DumperOptionsTest.java b/src/test/java/org/yaml/snakeyaml/DumperOptionsTest.java new file mode 100644 index 00000000..04d668d4 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/DumperOptionsTest.java @@ -0,0 +1,261 @@ +package org.yaml.snakeyaml; + +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import junit.framework.TestCase; + +import org.yaml.snakeyaml.emitter.Emitter; +import org.yaml.snakeyaml.error.YAMLException; + +public class DumperOptionsTest extends TestCase { + + public void testDefaultStyle() { + DumperOptions options = new DumperOptions(); + Yaml yaml = new Yaml(options); + assertEquals("abc\n", yaml.dump("abc")); + // string which looks like integer + assertEquals("'123'\n", yaml.dump("123")); + // + options.setDefaultStyle(DumperOptions.DefaultScalarStyle.DOUBLE_QUOTED); + yaml = new Yaml(options); + assertEquals("\"123\"\n", yaml.dump("123")); + // + options.setDefaultStyle(DumperOptions.DefaultScalarStyle.SINGLE_QUOTED); + yaml = new Yaml(options); + assertEquals("'123'\n", yaml.dump("123")); + // + options.setDefaultStyle(DumperOptions.DefaultScalarStyle.PLAIN); + yaml = new Yaml(options); + assertEquals("'123'\n", yaml.dump("123")); + assertEquals("abc\n", yaml.dump("abc")); + // null check + try { + options.setDefaultStyle(null); + fail("Null must not be accepted."); + } catch (NullPointerException e) { + assertEquals("Use DefaultScalarStyle enum.", e.getMessage()); + } + } + + public void testDefaultFlowStyle() { + Yaml yaml = new Yaml(); + List<Integer> list = new LinkedList<Integer>(); + list.add(1); + list.add(2); + list.add(3); + assertEquals("[1, 2, 3]\n", yaml.dump(list)); + // + DumperOptions options = new DumperOptions(); + options = new DumperOptions(); + options.setDefaultFlowStyle(DumperOptions.DefaultFlowStyle.FLOW); + yaml = new Yaml(options); + assertEquals("[1, 2, 3]\n", yaml.dump(list)); + // + options = new DumperOptions(); + options.setDefaultFlowStyle(DumperOptions.DefaultFlowStyle.BLOCK); + yaml = new Yaml(options); + assertEquals("- 1\n- 2\n- 3\n", yaml.dump(list)); + // null check + try { + options.setDefaultFlowStyle(null); + fail("Null must not be accepted."); + } catch (NullPointerException e) { + assertEquals("Use DefaultFlowStyle enum.", e.getMessage()); + } + } + + public void testDefaultFlowStyleNested() { + Yaml yaml = new Yaml(); + List<Integer> list = new LinkedList<Integer>(); + list.add(1); + list.add(2); + list.add(3); + Map<String, Object> map = new LinkedHashMap<String, Object>(); + map.put("a", "b"); + map.put("c", list); + assertEquals("a: b\nc: [1, 2, 3]\n", yaml.dump(map)); + // + DumperOptions options = new DumperOptions(); + options = new DumperOptions(); + options.setDefaultFlowStyle(DumperOptions.DefaultFlowStyle.FLOW); + yaml = new Yaml(options); + assertEquals("{a: b, c: [1, 2, 3]}\n", yaml.dump(map)); + // + options = new DumperOptions(); + options.setDefaultFlowStyle(DumperOptions.DefaultFlowStyle.BLOCK); + yaml = new Yaml(options); + assertEquals("a: b\nc:\n- 1\n- 2\n- 3\n", yaml.dump(map)); + } + + public void testCanonical() { + Yaml yaml = new Yaml(); + assertEquals("123\n", yaml.dump(123)); + // + DumperOptions options = new DumperOptions(); + options = new DumperOptions(); + options.setCanonical(true); + yaml = new Yaml(options); + assertEquals("---\n!!int \"123\"\n", yaml.dump(123)); + // + options = new DumperOptions(); + options.setCanonical(false); + yaml = new Yaml(options); + assertEquals("123\n", yaml.dump(123)); + } + + public void testIndent() { + Yaml yaml = new Yaml(); + List<Integer> list = new LinkedList<Integer>(); + list.add(1); + list.add(2); + DumperOptions options = new DumperOptions(); + options.setCanonical(true); + yaml = new Yaml(options); + assertEquals("---\n!!seq [\n !!int \"1\",\n !!int \"2\",\n]\n", yaml.dump(list)); + // + options.setIndent(4); + yaml = new Yaml(options); + assertEquals("---\n!!seq [\n !!int \"1\",\n !!int \"2\",\n]\n", yaml.dump(list)); + // + try { + options.setIndent(0); + fail(); + } catch (YAMLException e) { + assertTrue(true); + } + try { + options.setIndent(-2); + fail(); + } catch (YAMLException e) { + assertTrue(true); + } + try { + options.setIndent(11); + fail(); + } catch (YAMLException e) { + assertTrue(true); + } + // + assertTrue(Emitter.MIN_INDENT > 0); + assertTrue(Emitter.MIN_INDENT < Emitter.MAX_INDENT); + assertTrue(Emitter.MAX_INDENT < 20); + } + + public void testLineBreak() { + Yaml yaml = new Yaml(); + List<Integer> list = new LinkedList<Integer>(); + list.add(1); + list.add(2); + DumperOptions options = new DumperOptions(); + options.setCanonical(true); + yaml = new Yaml(options); + assertEquals("---\n!!seq [\n !!int \"1\",\n !!int \"2\",\n]\n", yaml.dump(list)); + // + options.setLineBreak(DumperOptions.LineBreak.WIN); + yaml = new Yaml(options); + String output = yaml.dump(list); + assertEquals("---\r\n!!seq [\r\n !!int \"1\",\r\n !!int \"2\",\r\n]\r\n", output); + // null check + try { + options.setLineBreak(null); + fail("Null must not be accepted."); + } catch (NullPointerException e) { + assertEquals("Specify line break.", e.getMessage()); + } + } + + public void testExplicitStart() { + Yaml yaml = new Yaml(); + List<Integer> list = new LinkedList<Integer>(); + list.add(1); + list.add(2); + list.add(3); + assertEquals("[1, 2, 3]\n", yaml.dump(list)); + // + DumperOptions options = new DumperOptions(); + options = new DumperOptions(); + options.setExplicitStart(true); + yaml = new Yaml(options); + assertEquals("--- [1, 2, 3]\n", yaml.dump(list)); + // + options.setExplicitEnd(true); + yaml = new Yaml(options); + assertEquals("--- [1, 2, 3]\n...\n", yaml.dump(list)); + } + + public void testVersion() { + Yaml yaml = new Yaml(); + List<Integer> list = new LinkedList<Integer>(); + list.add(1); + list.add(2); + list.add(3); + assertEquals("[1, 2, 3]\n", yaml.dump(list)); + // + DumperOptions options = new DumperOptions(); + options = new DumperOptions(); + options.setVersion(DumperOptions.Version.V1_1); + yaml = new Yaml(options); + assertEquals("%YAML 1.1\n--- [1, 2, 3]\n", yaml.dump(list)); + // + options.setVersion(DumperOptions.Version.V1_0); + yaml = new Yaml(options); + assertEquals("%YAML 1.0\n--- [1, 2, 3]\n", yaml.dump(list)); + } + + public void testTags() { + Yaml yaml = new Yaml(); + List<Integer> list = new LinkedList<Integer>(); + list.add(1); + list.add(2); + list.add(3); + assertEquals("[1, 2, 3]\n", yaml.dump(list)); + // + DumperOptions options = new DumperOptions(); + options = new DumperOptions(); + Map<String, String> tags = new LinkedHashMap<String, String>(); + tags.put("!foo!", "bar"); + options.setTags(tags); + yaml = new Yaml(options); + assertEquals("%TAG !foo! bar\n--- [1, 2, 3]\n", yaml.dump(list)); + // + options = new DumperOptions(); + tags.put("!yaml!", "tag:yaml.org,2002:"); + yaml = new Yaml(options); + assertEquals("foo\n", yaml.dump("foo")); + } + + public void testAllowUnicode() { + Yaml yaml = new Yaml(); + assertEquals("out: " + yaml.dump("\u00DCber"), "\u00DCber\n", yaml.dump("\u00DCber")); + // + DumperOptions options = new DumperOptions(); + options = new DumperOptions(); + options.setAllowUnicode(false); + yaml = new Yaml(options); + assertEquals("\"\\xdcber\"\n", yaml.dump("\u00DCber")); + } + + public void testSetRootTag() { + DumperOptions options = new DumperOptions(); + try { + options.setExplicitRoot(null); + fail("Root tag is required."); + } catch (NullPointerException e) { + assertEquals("Root tag must be specified.", e.getMessage()); + } + } + + public void testToString() { + DumperOptions.DefaultScalarStyle scalarStyle = DumperOptions.DefaultScalarStyle.LITERAL; + assertEquals("Scalar style: '|'", scalarStyle.toString()); + // + DumperOptions.DefaultFlowStyle flowStyle = DumperOptions.DefaultFlowStyle.BLOCK; + assertEquals("Flow style: 'false'", flowStyle.toString()); + // + DumperOptions.LineBreak lb = DumperOptions.LineBreak.LINUX; + assertEquals("Line break: LINUX", lb.toString()); + } +} diff --git a/src/test/java/org/yaml/snakeyaml/DumperTest.java b/src/test/java/org/yaml/snakeyaml/DumperTest.java new file mode 100644 index 00000000..ddbab0ee --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/DumperTest.java @@ -0,0 +1,82 @@ +package org.yaml.snakeyaml;
+
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+import java.io.IOException;
+import java.io.Writer;
+import java.util.LinkedList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+public class DumperTest extends TestCase {
+
+ public void testDump1() {
+ DumperOptions options = new DumperOptions();
+ options.setDefaultStyle(DumperOptions.DefaultScalarStyle.DOUBLE_QUOTED);
+ options.setExplicitStart(true);
+ options.setExplicitEnd(true);
+ List<Integer> list = new LinkedList<Integer>();
+ for (int i = 0; i < 3; i++) {
+ list.add(i);
+ }
+ Yaml yaml = new Yaml(options);
+ String output = yaml.dump(list);
+ assertEquals("---\n- !!int \"0\"\n- !!int \"1\"\n- !!int \"2\"\n...\n", output);
+ }
+
+ public void testDump2() {
+ DumperOptions options = new DumperOptions();
+ options.setExplicitStart(true);
+ List<Integer> list = new LinkedList<Integer>();
+ for (int i = 0; i < 3; i++) {
+ list.add(i);
+ }
+ Yaml yaml = new Yaml(options);
+ String output = yaml.dump(list);
+ assertEquals("--- [0, 1, 2]\n", output);
+ }
+
+ public void testDump3() {
+ DumperOptions options = new DumperOptions();
+ options.setDefaultStyle(DumperOptions.DefaultScalarStyle.SINGLE_QUOTED);
+ List<Integer> list = new LinkedList<Integer>();
+ for (int i = 0; i < 3; i++) {
+ list.add(i);
+ }
+ Yaml yaml = new Yaml(options);
+ String output = yaml.dump(list);
+ assertEquals("- !!int '0'\n- !!int '1'\n- !!int '2'\n", output);
+ }
+
+ public void testDumpException() {
+ Yaml yaml = new Yaml();
+ Writer writer = new ExceptionWriter1();
+ try {
+ yaml.dump("aaa1234567890", writer);
+ fail("Exception must be thrown.");
+ } catch (Exception e) {
+ assertEquals("java.io.IOException: write test failure.", e.getMessage());
+ }
+ }
+
+ private class ExceptionWriter1 extends Writer {
+ @Override
+ public void write(String str) throws IOException {
+ throw new IOException("write test failure.");
+ }
+
+ @Override
+ public void close() throws IOException {
+ }
+
+ @Override
+ public void flush() throws IOException {
+ }
+
+ @Override
+ public void write(char[] cbuf, int off, int len) throws IOException {
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/EnumBean.java b/src/test/java/org/yaml/snakeyaml/EnumBean.java new file mode 100644 index 00000000..c1bfb523 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/EnumBean.java @@ -0,0 +1,36 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml; + +import java.util.LinkedHashMap; + +public class EnumBean { + private int id; + private Suit suit; + private LinkedHashMap<Suit, Integer> map = new LinkedHashMap<Suit, Integer>(); + + public LinkedHashMap<Suit, Integer> getMap() { + return map; + } + + public void setMap(LinkedHashMap<Suit, Integer> map) { + this.map = map; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public Suit getSuit() { + return suit; + } + + public void setSuit(Suit suit) { + this.suit = suit; + } +} diff --git a/src/test/java/org/yaml/snakeyaml/EnumTest.java b/src/test/java/org/yaml/snakeyaml/EnumTest.java new file mode 100644 index 00000000..39dc0d93 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/EnumTest.java @@ -0,0 +1,175 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.EnumMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import junit.framework.TestCase; + +import org.yaml.snakeyaml.constructor.Constructor; + +public class EnumTest extends TestCase { + // Dumping + public void testDumpEnum() { + Yaml yaml = new Yaml(); + String output = yaml.dump(Suit.CLUBS); + assertEquals("!!org.yaml.snakeyaml.Suit 'CLUBS'\n", output); + } + + public void testDumpEnumArray() { + DumperOptions options = new DumperOptions(); + options.setDefaultFlowStyle(DumperOptions.DefaultFlowStyle.BLOCK); + Yaml yaml = new Yaml(options); + String output = yaml.dump(Suit.values()); + assertEquals( + "- !!org.yaml.snakeyaml.Suit 'CLUBS'\n- !!org.yaml.snakeyaml.Suit 'DIAMONDS'\n- !!org.yaml.snakeyaml.Suit 'HEARTS'\n- !!org.yaml.snakeyaml.Suit 'SPADES'\n", + output); + } + + public void testDumpEnumList() { + DumperOptions options = new DumperOptions(); + options.setDefaultFlowStyle(DumperOptions.DefaultFlowStyle.BLOCK); + Yaml yaml = new Yaml(options); + List<Suit> list = Arrays.asList(Suit.values()); + String output = yaml.dump(list); + assertEquals( + "- !!org.yaml.snakeyaml.Suit 'CLUBS'\n- !!org.yaml.snakeyaml.Suit 'DIAMONDS'\n- !!org.yaml.snakeyaml.Suit 'HEARTS'\n- !!org.yaml.snakeyaml.Suit 'SPADES'\n", + output); + } + + public void testDumpEnumListNoAnchor() { + DumperOptions options = new DumperOptions(); + options.setDefaultFlowStyle(DumperOptions.DefaultFlowStyle.BLOCK); + Yaml yaml = new Yaml(options); + List<Suit> list = new ArrayList<Suit>(3); + list.add(Suit.CLUBS); + list.add(Suit.DIAMONDS); + list.add(Suit.CLUBS); + String output = yaml.dump(list); + assertEquals( + "- !!org.yaml.snakeyaml.Suit 'CLUBS'\n- !!org.yaml.snakeyaml.Suit 'DIAMONDS'\n- !!org.yaml.snakeyaml.Suit 'CLUBS'\n", + output); + } + + public void testDumpEnumMap() { + DumperOptions options = new DumperOptions(); + options.setDefaultFlowStyle(DumperOptions.DefaultFlowStyle.BLOCK); + Yaml yaml = new Yaml(options); + Map<String, Suit> map = new LinkedHashMap<String, Suit>(); + map.put("c", Suit.CLUBS); + map.put("d", Suit.DIAMONDS); + String output = yaml.dump(map); + assertEquals( + "c: !!org.yaml.snakeyaml.Suit 'CLUBS'\nd: !!org.yaml.snakeyaml.Suit 'DIAMONDS'\n", + output); + } + + public void testDumpEnumMap2() { + DumperOptions options = new DumperOptions(); + options.setDefaultFlowStyle(DumperOptions.DefaultFlowStyle.BLOCK); + Yaml yaml = new Yaml(options); + Map<Suit, Integer> map = new EnumMap<Suit, Integer>(Suit.class); + map.put(Suit.CLUBS, 0); + map.put(Suit.DIAMONDS, 123); + String output = yaml.dump(map); + assertEquals( + "!!org.yaml.snakeyaml.Suit 'CLUBS': 0\n!!org.yaml.snakeyaml.Suit 'DIAMONDS': 123\n", + output); + } + + public void testDumpEnumBean() { + DumperOptions options = new DumperOptions(); + options.setDefaultFlowStyle(DumperOptions.DefaultFlowStyle.BLOCK); + Yaml yaml = new Yaml(options); + EnumBean bean = new EnumBean(); + bean.setId(17); + bean.setSuit(Suit.SPADES); + LinkedHashMap<Suit, Integer> map = new LinkedHashMap<Suit, Integer>(); + map.put(Suit.CLUBS, 1); + map.put(Suit.DIAMONDS, 2); + bean.setMap(map); + String output = yaml.dump(bean); + assertEquals( + "!!org.yaml.snakeyaml.EnumBean\nid: 17\nmap:\n !!org.yaml.snakeyaml.Suit 'CLUBS': 1\n !!org.yaml.snakeyaml.Suit 'DIAMONDS': 2\nsuit: SPADES\n", + output); + } + + // Loading + public void testLoadEnum() { + Yaml yaml = new Yaml(); + Suit suit = (Suit) yaml.load("!!org.yaml.snakeyaml.Suit 'CLUBS'\n"); + assertEquals(Suit.CLUBS, suit); + } + + @SuppressWarnings("unchecked") + public void testLoadEnumList() { + Yaml yaml = new Yaml(); + List<Suit> list = (List<Suit>) yaml + .load("- !!org.yaml.snakeyaml.Suit 'CLUBS'\n- !!org.yaml.snakeyaml.Suit 'DIAMONDS'\n- !!org.yaml.snakeyaml.Suit 'HEARTS'\n- !!org.yaml.snakeyaml.Suit 'SPADES'"); + assertEquals(4, list.size()); + assertEquals(Suit.CLUBS, list.get(0)); + assertEquals(Suit.DIAMONDS, list.get(1)); + assertEquals(Suit.HEARTS, list.get(2)); + assertEquals(Suit.SPADES, list.get(3)); + } + + @SuppressWarnings("unchecked") + public void testLoadEnumMap() { + Yaml yaml = new Yaml(); + Map<Integer, Suit> map = (Map<Integer, Suit>) yaml + .load("1: !!org.yaml.snakeyaml.Suit 'HEARTS'\n2: !!org.yaml.snakeyaml.Suit 'DIAMONDS'"); + assertEquals(2, map.size()); + assertEquals(Suit.HEARTS, map.get(1)); + assertEquals(Suit.DIAMONDS, map.get(2)); + } + + public void testLoadEnumBean() { + Yaml yaml = new Yaml(); + EnumBean bean = (EnumBean) yaml + .load("!!org.yaml.snakeyaml.EnumBean\nid: 174\nmap:\n !!org.yaml.snakeyaml.Suit 'CLUBS': 1\n !!org.yaml.snakeyaml.Suit 'DIAMONDS': 2\nsuit: CLUBS"); + + LinkedHashMap<Suit, Integer> map = new LinkedHashMap<Suit, Integer>(); + map.put(Suit.CLUBS, 1); + map.put(Suit.DIAMONDS, 2); + + assertEquals(Suit.CLUBS, bean.getSuit()); + assertEquals(174, bean.getId()); + assertEquals(map, bean.getMap()); + } + + public void testLoadEnumBean2() { + Constructor c = new Constructor(); + TypeDescription td = new TypeDescription(EnumBean.class); + td.putMapPropertyType("map", Suit.class, Object.class); + c.addTypeDescription(td); + Yaml yaml = new Yaml(new Loader(c)); + EnumBean bean = (EnumBean) yaml + .load("!!org.yaml.snakeyaml.EnumBean\nid: 174\nmap:\n CLUBS: 1\n DIAMONDS: 2\nsuit: CLUBS"); + + LinkedHashMap<Suit, Integer> map = new LinkedHashMap<Suit, Integer>(); + map.put(Suit.CLUBS, 1); + map.put(Suit.DIAMONDS, 2); + + assertEquals(Suit.CLUBS, bean.getSuit()); + assertEquals(174, bean.getId()); + assertEquals(map, bean.getMap()); + } + + public void testLoadWrongEnum() { + Yaml yaml = new Yaml(); + try { + yaml + .load("1: !!org.yaml.snakeyaml.Suit 'HEARTS'\n2: !!org.yaml.snakeyaml.Suit 'KOSYR'"); + fail("KOSYR is not Suit"); + } catch (Exception e) { + assertTrue("KOSYR must be reported", e.getMessage().contains( + "Unable to find enum value 'KOSYR' for enum")); + } + } +} diff --git a/src/test/java/org/yaml/snakeyaml/Example2_24Test.java b/src/test/java/org/yaml/snakeyaml/Example2_24Test.java new file mode 100644 index 00000000..fbb0e214 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/Example2_24Test.java @@ -0,0 +1,234 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.constructor.Construct;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.nodes.MappingNode;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.SequenceNode;
+import org.yaml.snakeyaml.representer.Represent;
+import org.yaml.snakeyaml.representer.Representer;
+
+/**
+ * Test Example 2.24 from the YAML specification
+ *
+ * @author py4fun
+ * @see http://yaml.org/spec/1.1/
+ */
+public class Example2_24Test extends TestCase {
+ class MyConstructor extends Constructor {
+ public MyConstructor() {
+ this.yamlConstructors.put("tag:clarkevans.com,2002:shape", new ConstructShape());
+ this.yamlConstructors.put("tag:clarkevans.com,2002:circle", new ConstructCircle());
+ this.yamlConstructors.put("tag:clarkevans.com,2002:line", new ConstructLine());
+ this.yamlConstructors.put("tag:clarkevans.com,2002:label", new ConstructLabel());
+ }
+
+ private class ConstructShape implements Construct {
+ @SuppressWarnings("unchecked")
+ public Object construct(Node node) {
+ SequenceNode snode = (SequenceNode) node;
+ List<Entity> values = (List<Entity>) constructSequence(snode);
+ Shape shape = new Shape(values);
+ return shape;
+ }
+ }
+
+ private class ConstructCircle implements Construct {
+ @SuppressWarnings("unchecked")
+ public Object construct(Node node) {
+ MappingNode mnode = (MappingNode) node;
+ Map values = (Map) constructMapping(mnode);
+ Circle circle = new Circle((Map) values.get("center"), (Integer) values
+ .get("radius"));
+ return circle;
+ }
+ }
+
+ private class ConstructLine implements Construct {
+ @SuppressWarnings("unchecked")
+ public Object construct(Node node) {
+ MappingNode mnode = (MappingNode) node;
+ Map values = (Map) constructMapping(mnode);
+ Line line = new Line((Map) values.get("start"), (Map) values.get("finish"));
+ return line;
+ }
+ }
+
+ private class ConstructLabel implements Construct {
+ @SuppressWarnings("unchecked")
+ public Object construct(Node node) {
+ MappingNode mnode = (MappingNode) node;
+ Map values = (Map) constructMapping(mnode);
+ Label label = new Label((Map) values.get("start"), (Integer) values.get("color"),
+ (String) values.get("text"));
+ return label;
+ }
+ }
+ }
+
+ class MyRepresenter extends Representer {
+ public MyRepresenter() {
+ this.representers.put(Shape.class, new RepresentShape());
+ this.representers.put(Circle.class, new RepresentCircle());
+ this.representers.put(Line.class, new RepresentLine());
+ this.representers.put(Label.class, new RepresentLabel());
+ this.representers.put(HexInteger.class, new RepresentHex());
+ }
+
+ private class RepresentShape implements Represent {
+ public Node representData(Object data) {
+ Shape shape = (Shape) data;
+ List<Entity> value = shape.getEntities();
+ return representSequence("!shape", value, Boolean.FALSE);
+ }
+ }
+
+ private class RepresentCircle implements Represent {
+ public Node representData(Object data) {
+ Circle circle = (Circle) data;
+ Map<String, Object> map = new TreeMap<String, Object>();
+ map.put("center", circle.getCenter());
+ map.put("radius", circle.getRadius());
+ return representMapping("!circle", map, Boolean.FALSE);
+ }
+ }
+
+ private class RepresentLine implements Represent {
+ public Node representData(Object data) {
+ Line line = (Line) data;
+ Map<String, Object> map = new TreeMap<String, Object>();
+ map.put("start", line.getStart());
+ map.put("finish", line.getFinish());
+ return representMapping("!line", map, Boolean.FALSE);
+ }
+ }
+
+ private class RepresentLabel implements Represent {
+ public Node representData(Object data) {
+ Label label = (Label) data;
+ Map<String, Object> map = new TreeMap<String, Object>();
+ map.put("start", label.getStart());
+ map.put("color", new HexInteger(label.getColor()));
+ map.put("text", label.getText());
+ return representMapping("!label", map, Boolean.FALSE);
+ }
+ }
+
+ private class RepresentHex implements Represent {
+ public Node representData(Object data) {
+ HexInteger hex = (HexInteger) data;
+ return representScalar("tag:yaml.org,2002:int", "0x"
+ + Integer.toHexString(hex.getColor()).toUpperCase(), null);
+ }
+ }
+ }
+
+ private class HexInteger {
+ private Integer color;
+
+ public HexInteger(Integer color) {
+ this.color = color;
+ }
+
+ public Integer getColor() {
+ return color;
+ }
+ }
+
+ private class Shape {
+ private List<Entity> entities;
+
+ public List<Entity> getEntities() {
+ return entities;
+ }
+
+ public Shape(List<Entity> entities) {
+ this.entities = entities;
+ }
+ }
+
+ private class Entity {
+ }
+
+ private class Circle extends Entity {
+ private Map<String, Integer> center;
+ private Integer radius;
+
+ public Circle(Map<String, Integer> center, Integer radius) {
+ this.center = center;
+ this.radius = radius;
+ }
+
+ public Map<String, Integer> getCenter() {
+ return center;
+ }
+
+ public Integer getRadius() {
+ return radius;
+ }
+ }
+
+ private class Line extends Entity {
+ private Map<String, Integer> start;
+ private Map<String, Integer> finish;
+
+ public Line(Map<String, Integer> start, Map<String, Integer> finish) {
+ this.start = start;
+ this.finish = finish;
+ }
+
+ public Map<String, Integer> getStart() {
+ return start;
+ }
+
+ public Map<String, Integer> getFinish() {
+ return finish;
+ }
+ }
+
+ private class Label extends Entity {
+ private Map<String, Integer> start;
+ private Integer color;
+ private String text;
+
+ public Label(Map<String, Integer> start, Integer color, String text) {
+ this.start = start;
+ this.color = color;
+ this.text = text;
+ }
+
+ public Map<String, Integer> getStart() {
+ return start;
+ }
+
+ public Integer getColor() {
+ return color;
+ }
+
+ public String getText() {
+ return text;
+ }
+ }
+
+ public void testExample_2_24() throws IOException {
+ Loader loader = new Loader(new MyConstructor());
+ Yaml yaml = new Yaml(loader);
+ Shape shape = (Shape) yaml.load(Util.getLocalResource("specification/example2_24.yaml"));
+ assertNotNull(shape);
+ Dumper dumper = new Dumper(new MyRepresenter(), new DumperOptions());
+ yaml = new Yaml(dumper);
+ String output = yaml.dump(shape);
+ String etalon = Util.getLocalResource("specification/example2_24_dumped.yaml");
+ assertEquals(etalon, output);
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/Example2_27Test.java b/src/test/java/org/yaml/snakeyaml/Example2_27Test.java new file mode 100644 index 00000000..ec56fff7 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/Example2_27Test.java @@ -0,0 +1,35 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml;
+
+import java.io.IOException;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.constructor.Constructor;
+
+/**
+ * Test Example 2.27 from the YAML specification
+ *
+ * @author py4fun
+ * @see http://yaml.org/spec/1.1/
+ */
+public class Example2_27Test extends TestCase {
+
+ public void testExample_2_27() throws IOException {
+ Loader loader = new Loader(new Constructor(Invoice.class));
+ Yaml yaml = new Yaml(loader);
+ Invoice invoice = (Invoice) yaml.load(Util
+ .getLocalResource("specification/example2_27.yaml"));
+ assertNotNull(invoice);
+ Person billTo = invoice.billTo;
+ assertEquals("Dumars", billTo.family);
+ Dumper dumper = new Dumper(new DumperOptions());
+ yaml = new Yaml(dumper);
+ String output = yaml.dump(invoice);
+ System.out.println(output);
+ String etalon = Util.getLocalResource("specification/example2_27_dumped.yaml");
+ assertEquals(etalon, output);
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/Invoice.java b/src/test/java/org/yaml/snakeyaml/Invoice.java new file mode 100644 index 00000000..66c585be --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/Invoice.java @@ -0,0 +1,18 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml;
+
+import java.util.List;
+
+public class Invoice {
+ public Integer invoice; // invoice
+ public String date; // date
+ public Person billTo;// bill-to
+ public Person shipTo;// ship-to
+ public List<Product> product;
+ public Float tax;
+ public Float total;
+ public String comments;
+
+}
\ No newline at end of file diff --git a/src/test/java/org/yaml/snakeyaml/JavaBeanParserTest.java b/src/test/java/org/yaml/snakeyaml/JavaBeanParserTest.java new file mode 100644 index 00000000..2f2f18de --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/JavaBeanParserTest.java @@ -0,0 +1,95 @@ +package org.yaml.snakeyaml;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.StringReader;
+
+import junit.framework.TestCase;
+
+public class JavaBeanParserTest extends TestCase {
+
+ public void testLoadString() {
+ Bean bean = new Bean();
+ bean.setId(3);
+ bean.setName("Test me.");
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(bean);
+ assertEquals("!!org.yaml.snakeyaml.JavaBeanParserTest$Bean {id: 3, name: Test me.}\n",
+ output);
+ Bean parsed = JavaBeanParser.load(output, Bean.class);
+ assertEquals(3, parsed.getId());
+ assertEquals("Test me.", parsed.getName());
+ // Runtime definition is more important
+ Bean2 parsed2 = JavaBeanParser.load(output, Bean2.class);
+ assertEquals(3, parsed2.getId());
+ assertEquals("Test me.", parsed2.getName());
+ assertFalse(parsed2.isValid());
+ }
+
+ public void testLoadInputStream() {
+ String yaml = "!!org.yaml.snakeyaml.JavaBeanParserTest$Bean {id: 3, name: Test me.}\n";
+ InputStream input = new ByteArrayInputStream(yaml.getBytes());
+ Bean parsed = JavaBeanParser.load(input, Bean.class);
+ assertEquals(3, parsed.getId());
+ assertEquals("Test me.", parsed.getName());
+ }
+
+ public void testLoadReader() {
+ String yaml = "!!org.yaml.snakeyaml.JavaBeanParserTest$Bean {id: 3, name: Test me.}\n";
+ java.io.Reader input = new StringReader(yaml);
+ Bean parsed = JavaBeanParser.load(input, Bean.class);
+ assertEquals(3, parsed.getId());
+ assertEquals("Test me.", parsed.getName());
+ }
+
+ public static class Bean {
+ private String name;
+ private int id;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+ }
+
+ public static class Bean2 {
+ private String name;
+ private int id;
+ private boolean valid;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public boolean isValid() {
+ return valid;
+ }
+
+ public void setValid(boolean valid) {
+ this.valid = valid;
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/ParallelTest.java b/src/test/java/org/yaml/snakeyaml/ParallelTest.java new file mode 100644 index 00000000..1de2f2b8 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/ParallelTest.java @@ -0,0 +1,83 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml;
+
+import java.io.IOException;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.error.YAMLException;
+
+/**
+ * Test that Yaml instances are independent and can be used in multiple threads.
+ */
+public class ParallelTest extends TestCase {
+ private int progress = 0;
+ private int MAX = 5;
+
+ public void testPerfomance() throws IOException {
+ String doc = Util.getLocalResource("specification/example2_27.yaml");
+ for (int i = 0; i < MAX; i++) {
+ Worker worker = new Worker(i, doc);
+ Thread thread = new Thread(worker);
+ thread.start();
+ }
+ while (progress < MAX - 1) {
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ fail(e.getMessage());
+ }
+ }
+ }
+
+ private class Worker implements Runnable {
+ private int id;
+ private String doc;
+
+ public Worker(int id, String doc) {
+ this.id = id;
+ this.doc = doc;
+ }
+
+ public void run() {
+ System.out.println("Started: " + id);
+ Loader loader = new Loader(new Constructor(Invoice.class));
+ Yaml yaml = new Yaml(loader);
+ long time1 = System.currentTimeMillis();
+ int cycles = 200;
+ for (int i = 0; i < cycles; i++) {
+ Invoice invoice = (Invoice) yaml.load(doc);
+ assertNotNull(invoice);
+ }
+ long time2 = System.currentTimeMillis();
+ float duration = (time2 - time1) / (float) cycles;
+ System.out.println("Duration of " + id + " was " + duration + " ms/load.");
+ progress++;
+ }
+ }
+
+ public void testSharedLoader() throws IOException {
+ Loader loader = new Loader(new Constructor(Invoice.class));
+ new Yaml(loader);
+ try {
+ new Yaml(loader);
+ fail("Loader cannot be shared.");
+ } catch (YAMLException e) {
+ assertEquals("Loader cannot be shared.", e.getMessage());
+ }
+ }
+
+ public void testSharedDumper() throws IOException {
+ Dumper dumper = new Dumper(new DumperOptions());
+ new Yaml(dumper);
+ try {
+ new Yaml(dumper);
+ fail("Dumper cannot be shared.");
+ } catch (YAMLException e) {
+ assertEquals("Dumper cannot be shared.", e.getMessage());
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/Person.java b/src/test/java/org/yaml/snakeyaml/Person.java new file mode 100644 index 00000000..d231a18e --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/Person.java @@ -0,0 +1,10 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml;
+
+public class Person {
+ public String given;
+ public String family;
+ public Address address;
+}
\ No newline at end of file diff --git a/src/test/java/org/yaml/snakeyaml/Product.java b/src/test/java/org/yaml/snakeyaml/Product.java new file mode 100644 index 00000000..1417a680 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/Product.java @@ -0,0 +1,11 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml;
+
+public class Product {
+ public String sku;
+ public Integer quantity;
+ public String description;
+ public Float price;
+}
\ No newline at end of file diff --git a/src/test/java/org/yaml/snakeyaml/StressTest.java b/src/test/java/org/yaml/snakeyaml/StressTest.java new file mode 100644 index 00000000..708366ad --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/StressTest.java @@ -0,0 +1,60 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml;
+
+import java.io.IOException;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.constructor.Constructor;
+
+public class StressTest extends TestCase {
+ String doc;
+
+ public void setUp() throws IOException {
+ doc = Util.getLocalResource("specification/example2_27.yaml");
+ }
+
+ public void testPerformance() throws IOException {
+ long time1 = System.currentTimeMillis();
+ new Yaml(new Loader(new Constructor(Invoice.class)));
+ long time2 = System.currentTimeMillis();
+ float duration = time2 - time1;
+ System.out.println("Init was " + duration + " ms.");
+
+ Yaml yaml = new Yaml(new Loader(new Constructor(Invoice.class)));
+ time1 = System.currentTimeMillis();
+ yaml.load(doc);
+ time2 = System.currentTimeMillis();
+ duration = time2 - time1;
+ System.out.println("\nSingle load was " + duration + " ms.");
+
+ yaml = new Yaml(new Loader(new Constructor(Invoice.class)));
+ int[] range = new int[] { 1000, 2000 };
+ System.out.println("\nOne instance.");
+ for (int number : range) {
+ time1 = System.currentTimeMillis();
+ for (int i = 0; i < number; i++) {
+ yaml.load(doc);
+ }
+ time2 = System.currentTimeMillis();
+ duration = (time2 - time1) / (float) number;
+ System.out.println("Duration for r=" + number + " was " + duration + " ms/load.");
+ assertTrue("duration=" + duration, duration < 5);
+ }
+
+ System.out.println("\nMany instances.");
+ for (int number : range) {
+ time1 = System.currentTimeMillis();
+ for (int i = 0; i < number; i++) {
+ yaml = new Yaml(new Loader(new Constructor(Invoice.class)));
+ yaml.load(doc);
+ }
+ time2 = System.currentTimeMillis();
+ duration = (time2 - time1) / (float) number;
+ System.out.println("Duration for r=" + number + " was " + duration + " ms/load.");
+ assertTrue("duration=" + duration, duration < 5);
+ }
+ }
+}
\ No newline at end of file diff --git a/src/test/java/org/yaml/snakeyaml/Suit.java b/src/test/java/org/yaml/snakeyaml/Suit.java new file mode 100644 index 00000000..9a409960 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/Suit.java @@ -0,0 +1,8 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml;
+
+public enum Suit {
+ CLUBS, DIAMONDS, HEARTS, SPADES
+}
\ No newline at end of file diff --git a/src/test/java/org/yaml/snakeyaml/TypeDescriptionTest.java b/src/test/java/org/yaml/snakeyaml/TypeDescriptionTest.java new file mode 100644 index 00000000..fe7d7be0 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/TypeDescriptionTest.java @@ -0,0 +1,21 @@ +package org.yaml.snakeyaml;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.constructor.ArrayTagsTest.CarWithArray;
+
+public class TypeDescriptionTest extends TestCase {
+
+ public void testSetTag() {
+ TypeDescription descr = new TypeDescription(TypeDescriptionTest.class);
+ descr.setTag("!bla");
+ assertEquals("!bla", descr.getTag());
+ }
+
+ public void testToString() {
+ TypeDescription carDescription = new TypeDescription(CarWithArray.class, "!car");
+ assertEquals(
+ "TypeDescription for class org.yaml.snakeyaml.constructor.ArrayTagsTest$CarWithArray (tag='!car')",
+ carDescription.toString());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/Util.java b/src/test/java/org/yaml/snakeyaml/Util.java new file mode 100644 index 00000000..2c87874a --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/Util.java @@ -0,0 +1,39 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class Util {
+
+ public static String getLocalResource(String theName) throws IOException {
+ InputStream input;
+ input = YamlDocument.class.getClassLoader().getResourceAsStream(theName);
+ if (input == null) {
+ throw new RuntimeException("Can not find " + theName);
+ }
+ BufferedInputStream is = new BufferedInputStream(input);
+ StringBuffer buf = new StringBuffer(3000);
+ int i;
+ try {
+ while ((i = is.read()) != -1) {
+ buf.append((char) i);
+ }
+ } finally {
+ is.close();
+ }
+ String resource = buf.toString();
+ // convert EOLs
+ String[] lines = resource.split("\\r?\\n");
+ StringBuffer buffer = new StringBuffer();
+ for (int j = 0; j < lines.length; j++) {
+ buffer.append(lines[j]);
+ buffer.append("\n");
+ }
+ return buffer.toString();
+ }
+
+}
diff --git a/src/test/java/org/yaml/snakeyaml/YamlDocument.java b/src/test/java/org/yaml/snakeyaml/YamlDocument.java new file mode 100644 index 00000000..1b5443e8 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/YamlDocument.java @@ -0,0 +1,71 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStreamWriter;
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
+
+import org.yaml.snakeyaml.constructor.Constructor;
+
+public class YamlDocument {
+ public static final String ROOT = "specification/";
+ private String source;
+ private String presentation;
+ private Object nativeData;
+
+ public YamlDocument(String sourceName, boolean check, Constructor constructor) {
+ InputStream input = YamlDocument.class.getClassLoader().getResourceAsStream(
+ ROOT + sourceName);
+ if (constructor == null) {
+ constructor = new Constructor();
+ }
+ Loader loader = new Loader(constructor);
+ Yaml yaml = new Yaml(loader);
+ nativeData = yaml.load(input);
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+ Charset charset = Charset.forName("UTF-8");
+ yaml.dump(nativeData, new OutputStreamWriter(output, charset));
+ try {
+ presentation = output.toString(charset.name());
+ source = Util.getLocalResource(ROOT + sourceName);
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ // try to read generated presentation to prove that the presentation
+ // is identical to the source
+ Object result = yaml.load(presentation);
+ if (check && !nativeData.equals(result)) {
+ throw new RuntimeException("Generated presentation is not valid: " + presentation);
+ }
+ }
+
+ public YamlDocument(String sourceName, boolean check) {
+ this(sourceName, check, null);
+ }
+
+ public YamlDocument(String sourceName) {
+ this(sourceName, true);
+ }
+
+ public String getSource() {
+ return source;
+ }
+
+ public String getPresentation() {
+ return presentation;
+ }
+
+ public Object getNativeData() {
+ if (nativeData == null) {
+ throw new NullPointerException("No object is parsed.");
+ }
+ return nativeData;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/YamlStream.java b/src/test/java/org/yaml/snakeyaml/YamlStream.java new file mode 100644 index 00000000..e4e9e099 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/YamlStream.java @@ -0,0 +1,83 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml;
+
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.OutputStreamWriter;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.AssertionFailedError;
+
+public class YamlStream {
+ private List<Object> nativeData = new ArrayList<Object>();
+
+ @SuppressWarnings("unchecked")
+ public YamlStream(String sourceName) {
+ InputStream input = YamlDocument.class.getClassLoader().getResourceAsStream(
+ YamlDocument.ROOT + sourceName);
+ Yaml yaml = new Yaml();
+ for (Object document : yaml.loadAll(input)) {
+ nativeData.add(document);
+ }
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+ yaml.dumpAll(nativeData.iterator(), new OutputStreamWriter(output));
+ String presentation;
+ try {
+ presentation = output.toString("UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ // try to read generated presentation to prove that the presentation
+ // is identical to the source
+ List<Object> parsedNativeData = new ArrayList<Object>();
+ for (Object document : yaml.loadAll(presentation)) {
+ parsedNativeData.add(document);
+ }
+ if (nativeData.getClass() != parsedNativeData.getClass()) {
+ throw new AssertionFailedError("Different class: " + parsedNativeData.getClass());
+ }
+ if (nativeData.size() != parsedNativeData.size()) {
+ throw new AssertionFailedError("Different size.");
+ }
+ Iterator piterator = parsedNativeData.iterator();
+ Iterator niterator = nativeData.iterator();
+ while (piterator.hasNext()) {
+ Object obj1 = niterator.next();
+ Object obj2 = piterator.next();
+ if (obj1 instanceof Map) {
+ Map map1 = (Map) obj1;
+ Map map2 = (Map) obj2;
+ if (!map1.keySet().equals(map2.keySet())) {
+ throw new AssertionFailedError("Keyset: " + map1.keySet() + "; but was: "
+ + map2.keySet());
+ }
+ for (Iterator iterator = map1.keySet().iterator(); iterator.hasNext();) {
+ Object key = (Object) iterator.next();
+ Object o1 = map1.get(key);
+ Object o2 = map2.get(key);
+ if (!o1.equals(o2)) {
+ throw new AssertionFailedError("Values: " + o1 + "; but was: " + o2);
+ }
+ }
+ }
+ if (!obj1.equals(obj2)) {
+ throw new AssertionFailedError("Expected: " + obj1 + "; but was: " + obj2);
+ }
+ }
+ if (!parsedNativeData.equals(nativeData)) {
+ throw new AssertionFailedError("Generated presentation is not the same: "
+ + presentation);
+ }
+ }
+
+ public List<Object> getNativeData() {
+ return nativeData;
+ }
+
+}
diff --git a/src/test/java/org/yaml/snakeyaml/YamlTest.java b/src/test/java/org/yaml/snakeyaml/YamlTest.java new file mode 100644 index 00000000..0041199e --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/YamlTest.java @@ -0,0 +1,18 @@ +package org.yaml.snakeyaml;
+
+import junit.framework.TestCase;
+
+public class YamlTest extends TestCase {
+
+ public void testSetNoName() {
+ Yaml yaml = new Yaml();
+ assertTrue(yaml.toString().matches("Yaml:\\d+"));
+ }
+
+ public void testSetName() {
+ Yaml yaml = new Yaml();
+ yaml.setName("REST");
+ assertEquals("REST", yaml.getName());
+ assertEquals("REST", yaml.toString());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/composer/ComposerImplTest.java b/src/test/java/org/yaml/snakeyaml/composer/ComposerImplTest.java new file mode 100644 index 00000000..5633c1ca --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/composer/ComposerImplTest.java @@ -0,0 +1,37 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.composer;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.nodes.MappingNode;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.parser.Parser;
+import org.yaml.snakeyaml.parser.ParserImpl;
+import org.yaml.snakeyaml.reader.Reader;
+import org.yaml.snakeyaml.resolver.Resolver;
+
+public class ComposerImplTest extends TestCase {
+
+ public void testGetNode() {
+ String data = "american:\n - Boston Red Sox";
+ Node node = compose(data);
+ assertNotNull(node);
+ assertTrue(node instanceof MappingNode);
+ // System.out.println(node);
+ String data2 = "---\namerican:\n- Boston Red Sox";
+ Node node2 = compose(data2);
+ assertNotNull(node2);
+ assertFalse(node.equals(node2));
+ }
+
+ private Node compose(String data) {
+ Reader reader = new Reader(data);
+ Parser parser = new ParserImpl(reader);
+ Resolver resolver = new Resolver();
+ Composer composer = new Composer(parser, resolver);
+ Node node = composer.getSingleNode();
+ return node;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/constructor/ArrayTagsTest.java b/src/test/java/org/yaml/snakeyaml/constructor/ArrayTagsTest.java new file mode 100644 index 00000000..5576b365 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/constructor/ArrayTagsTest.java @@ -0,0 +1,89 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.constructor;
+
+import java.io.IOException;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Loader;
+import org.yaml.snakeyaml.TypeDescription;
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+
+public class ArrayTagsTest extends TestCase {
+
+ public void testDefaultRepresenter() throws IOException {
+ CarWithArray car = new CarWithArray();
+ car.setPlate("12-XP-F4");
+ Wheel[] wheels = new Wheel[5];
+ for (int i = 1; i < 6; i++) {
+ Wheel wheel = new Wheel();
+ wheel.setId(i);
+ wheels[i - 1] = wheel;
+ }
+ car.setWheels(wheels);
+ assertEquals(Util.getLocalResource("constructor/cararray-with-tags.yaml"), new Yaml()
+ .dump(car));
+ }
+
+ public void testLoadClassTag() throws IOException {
+ Constructor constructor = new Constructor();
+ constructor.addTypeDescription(new TypeDescription(Car.class, "!car"));
+ Loader loader = new Loader(constructor);
+ Yaml yaml = new Yaml(loader);
+ Car car = (Car) yaml.load(Util.getLocalResource("constructor/car-without-tags.yaml"));
+ assertEquals("12-XP-F4", car.getPlate());
+ List<Wheel> wheels = car.getWheels();
+ assertNotNull(wheels);
+ assertEquals(5, wheels.size());
+ }
+
+ public void testNullDescription() throws IOException {
+ Constructor constructor = new Constructor();
+ try {
+ constructor.addTypeDescription(null);
+ fail("Description is required.");
+ } catch (Exception e) {
+ assertEquals("TypeDescription is required.", e.getMessage());
+ }
+ }
+
+ public void testLoadClassNoRoot() throws IOException {
+ Constructor constructor = new Constructor();
+ TypeDescription carDescription = new TypeDescription(CarWithArray.class);
+ carDescription.setRoot(true);
+ constructor.addTypeDescription(carDescription);
+ Loader loader = new Loader(constructor);
+ Yaml yaml = new Yaml(loader);
+ CarWithArray car = (CarWithArray) yaml.load(Util
+ .getLocalResource("constructor/car-no-root-class.yaml"));
+ assertEquals("12-XP-F4", car.getPlate());
+ Wheel[] wheels = car.getWheels();
+ assertNotNull(wheels);
+ assertEquals(5, wheels.length);
+ }
+
+ public static class CarWithArray {
+ private String plate;
+ private Wheel[] wheels;
+
+ public String getPlate() {
+ return plate;
+ }
+
+ public void setPlate(String plate) {
+ this.plate = plate;
+ }
+
+ public Wheel[] getWheels() {
+ return wheels;
+ }
+
+ public void setWheels(Wheel[] wheels) {
+ this.wheels = wheels;
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/constructor/BeanConstructorTest.java b/src/test/java/org/yaml/snakeyaml/constructor/BeanConstructorTest.java new file mode 100644 index 00000000..57d273c5 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/constructor/BeanConstructorTest.java @@ -0,0 +1,228 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.constructor;
+
+import java.io.IOException;
+import java.math.BigInteger;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Loader;
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.error.YAMLException;
+
+public class BeanConstructorTest extends TestCase {
+
+ public void testPrimitivesConstructor() throws IOException {
+ Loader loader = new Loader(new Constructor(TestBean1.class));
+ Yaml yaml = new Yaml(loader);
+ String document = Util.getLocalResource("constructor/test-primitives1.yaml");
+ System.out.println(document);
+ TestBean1 result = (TestBean1) yaml.load(document);
+ assertNotNull(result);
+ assertEquals(new Byte((byte) 1), result.getByteClass());
+ assertEquals((byte) -3, result.getBytePrimitive());
+ assertEquals(new Short((short) 0), result.getShortClass());
+ assertEquals((short) -13, result.getShortPrimitive());
+ assertEquals(new Integer(5), result.getInteger());
+ assertEquals(17, result.getIntPrimitive());
+ assertEquals("the text", result.getText());
+ assertEquals("13", result.getId());
+ assertEquals(new Long(11111111111L), result.getLongClass());
+ assertEquals(9999999999L, result.getLongPrimitive());
+ assertEquals(Boolean.TRUE, result.getBooleanClass());
+ assertTrue(result.isBooleanPrimitive());
+ assertEquals(new Character('2'), result.getCharClass());
+ assertEquals('#', result.getCharPrimitive());
+ assertEquals(new BigInteger("1234567890123456789012345678901234567890"), result
+ .getBigInteger());
+ assertEquals(new Float(2), result.getFloatClass());
+ assertEquals(new Float(3.1416), result.getFloatPrimitive());
+ assertEquals(new Double(4), result.getDoubleClass());
+ assertEquals(new Double(11200), result.getDoublePrimitive());
+ assertEquals(1199836800000L, result.getDate().getTime());
+ assertEquals("public", result.publicField);
+ //
+ DumperOptions options = new DumperOptions();
+ options.setDefaultFlowStyle(DumperOptions.DefaultFlowStyle.BLOCK);
+ Yaml yamlToDump = new Yaml(options);
+ String output = yamlToDump.dump(result);
+ System.out.println(output);
+ TestBean1 result2 = (TestBean1) yaml.load(output);
+ assertNotNull(result2);
+ TestBean1 result3 = (TestBean1) new Yaml().load(output);
+ assertNotNull(result3);
+ }
+
+ public void testNoClassConstructor() {
+ try {
+ new Loader(new Constructor((Class<? extends Object>) null));
+ fail("Class must be provided.");
+ } catch (NullPointerException e) {
+ assertEquals("Root type must be provided.", e.getMessage());
+ }
+ }
+
+ public void testNoClassConstructorString() throws ClassNotFoundException {
+ try {
+ new Loader(new Constructor((String) null));
+ fail("Class must be provided.");
+ } catch (NullPointerException e) {
+ assertEquals("Root type must be provided.", e.getMessage());
+ }
+ }
+
+ public void testNoClassConstructorEmptyString() throws ClassNotFoundException {
+ try {
+ new Loader(new Constructor(" "));
+ fail("Class must be provided.");
+ } catch (YAMLException e) {
+ assertEquals("Root type must be provided.", e.getMessage());
+ }
+ }
+
+ public void testCharacter() throws IOException {
+ Loader loader = new Loader(new Constructor(TestBean1.class));
+ Yaml yaml = new Yaml(loader);
+ String document = "charClass: id";
+ try {
+ yaml.load(document);
+ fail("Only one char must be allowed.");
+ } catch (Exception e) {
+ assertTrue(e.getMessage(), e.getMessage().contains(
+ "Invalid node Character: 'id'; length: 2"));
+ }
+ document = "charClass: #";
+ try {
+ yaml.load(document);
+ fail("Only one char must be allowed.");
+ } catch (Exception e) {
+ assertTrue(e.getMessage(), e.getMessage().contains(
+ "Invalid node Character: ''; length: 0"));
+ }
+ document = "charClass: ''";
+ try {
+ yaml.load(document);
+ fail("Only one char must be allowed.");
+ } catch (Exception e) {
+ assertTrue(e.getMessage(), e.getMessage().contains(
+ "Invalid node Character: ''; length: 0"));
+ }
+ document = "charClass:\n";
+ try {
+ yaml.load(document);
+ fail("Only one char must be allowed.");
+ } catch (Exception e) {
+ assertTrue(e.getMessage(), e.getMessage().contains(
+ "Invalid node Character: ''; length: 0"));
+ }
+
+ }
+
+ public void testNoEmptyConstructor() throws IOException {
+ Loader loader = new Loader(new Constructor(TestBean2.class));
+ Yaml yaml = new Yaml(loader);
+ String document = "text: qwerty";
+ try {
+ yaml.load(document);
+ fail("No empty constructor available");
+ } catch (Exception e) {
+ assertTrue(e.getMessage(), e.getMessage().contains("InstantiationException"));
+ }
+ }
+
+ private class TestBean2 {
+ private String text;
+
+ public TestBean2(String text) {
+ this.text = text;
+ }
+
+ public String getText() {
+ return text;
+ }
+
+ public void setText(String text) {
+ this.text = text;
+ }
+ }
+
+ public void testPrivateMethod() throws IOException {
+ Loader loader = new Loader(new Constructor(TestBean3.class));
+ Yaml yaml = new Yaml(loader);
+ String document = "text: qwerty";
+ try {
+ yaml.load(document);
+ fail("Private method cannot be called.");
+ } catch (Exception e) {
+ assertTrue(e.getMessage(), e.getMessage().contains("InstantiationException"));
+ }
+ }
+
+ private class TestBean3 {
+ private String text;
+
+ public TestBean3() {
+ setText("123");
+ }
+
+ public String getText() {
+ return text;
+ }
+
+ private void setText(String text) {
+ this.text = text;
+ }
+ }
+
+ public void testKeyNotScalar() throws IOException {
+ Loader loader = new Loader(new Constructor(TestBean1.class));
+ Yaml yaml = new Yaml(loader);
+ String document = "[1, 2]: qwerty";
+ try {
+ yaml.load(document);
+ fail("Keys must be scalars.");
+ } catch (Exception e) {
+ assertTrue(e.getMessage(), e.getMessage().contains("Keys must be scalars but found"));
+ }
+ }
+
+ public void testInvalidKey() throws IOException {
+ Loader loader = new Loader(new Constructor(TestBean1.class));
+ Yaml yaml = new Yaml(loader);
+ String document = "something: qwerty";
+ try {
+ yaml.load(document);
+ fail("Non-existing property must fail.");
+ } catch (Exception e) {
+ assertTrue(e.getMessage(), e.getMessage().contains(
+ "Unable to find property 'something'"));
+ }
+ }
+
+ public void testStaticField() throws IOException {
+ Loader loader = new Loader(new Constructor(TestBean1.class));
+ Yaml yaml = new Yaml(loader);
+ String document = "staticInteger: 123";
+ try {
+ yaml.load(document);
+ fail("Staic variables must not be used.");
+ } catch (Exception e) {
+ assertTrue(e.getMessage(), e.getMessage().contains(
+ "Unable to find property 'staticInteger'"));
+ }
+ }
+
+ public void testScalarContructor() throws IOException {
+ Loader loader = new Loader(new Constructor(Parent1.class));
+ Yaml yaml = new Yaml(loader);
+ String document = "id: 123\nchild: 25";
+ Parent1 parent = (Parent1) yaml.load(document);
+ assertEquals("123", parent.getId());
+ Child1 child = parent.getChild();
+ assertEquals(new Integer(25), child.getCode());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/constructor/Car.java b/src/test/java/org/yaml/snakeyaml/constructor/Car.java new file mode 100644 index 00000000..5e5b6f18 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/constructor/Car.java @@ -0,0 +1,27 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.constructor;
+
+import java.util.List;
+
+public class Car {
+ private String plate;
+ private List<Wheel> wheels;
+
+ public String getPlate() {
+ return plate;
+ }
+
+ public void setPlate(String plate) {
+ this.plate = plate;
+ }
+
+ public List<Wheel> getWheels() {
+ return wheels;
+ }
+
+ public void setWheels(List<Wheel> wheels) {
+ this.wheels = wheels;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/constructor/Child1.java b/src/test/java/org/yaml/snakeyaml/constructor/Child1.java new file mode 100644 index 00000000..eac79867 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/constructor/Child1.java @@ -0,0 +1,16 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.constructor;
+
+public class Child1 {
+ private Integer code;
+
+ public Child1(Integer code) {
+ this.code = code;
+ }
+
+ public Integer getCode() {
+ return code;
+ }
+}
\ No newline at end of file diff --git a/src/test/java/org/yaml/snakeyaml/constructor/ClassTagsTest.java b/src/test/java/org/yaml/snakeyaml/constructor/ClassTagsTest.java new file mode 100644 index 00000000..4bc80c0b --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/constructor/ClassTagsTest.java @@ -0,0 +1,101 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.constructor;
+
+import java.io.IOException;
+import java.util.LinkedList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Dumper;
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Loader;
+import org.yaml.snakeyaml.TypeDescription;
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.error.YAMLException;
+import org.yaml.snakeyaml.representer.Representer;
+
+public class ClassTagsTest extends TestCase {
+
+ public void testDefaultRepresenter() throws IOException {
+ Car car = new Car();
+ car.setPlate("12-XP-F4");
+ List<Wheel> wheels = new LinkedList<Wheel>();
+ for (int i = 1; i < 6; i++) {
+ Wheel wheel = new Wheel();
+ wheel.setId(i);
+ wheels.add(wheel);
+ }
+ car.setWheels(wheels);
+ assertEquals(Util.getLocalResource("constructor/car-with-tags.yaml"), new Yaml().dump(car));
+ }
+
+ public void testDumpClassTag() throws IOException {
+ Car car = new Car();
+ car.setPlate("12-XP-F4");
+ List<Wheel> wheels = new LinkedList<Wheel>();
+ for (int i = 1; i < 6; i++) {
+ Wheel wheel = new Wheel();
+ wheel.setId(i);
+ wheels.add(wheel);
+ }
+ car.setWheels(wheels);
+ Representer representer = new Representer();
+ representer.addTypeDescription(new TypeDescription(Car.class, "!car"));
+ representer.addTypeDescription(new TypeDescription(Wheel.class, "tag:yaml.org,2002:map"));
+ Dumper dumper = new Dumper(representer, new DumperOptions());
+ Yaml yaml = new Yaml(dumper);
+ String output = yaml.dump(car);
+ assertEquals(Util.getLocalResource("constructor/car-without-tags.yaml"), output);
+ }
+
+ public void testLoadUnknounClassTag() throws IOException {
+ try {
+ Yaml yaml = new Yaml();
+ yaml.load(Util.getLocalResource("constructor/car-without-tags.yaml"));
+ fail("Must fail because of unknown tag: !car");
+ } catch (YAMLException e) {
+ assertTrue(e.getMessage().contains("Unknown tag: !car"));
+ }
+
+ }
+
+ public void testLoadClassTag() throws IOException {
+ Constructor constructor = new Constructor();
+ constructor.addTypeDescription(new TypeDescription(Car.class, "!car"));
+ Loader loader = new Loader(constructor);
+ Yaml yaml = new Yaml(loader);
+ Car car = (Car) yaml.load(Util.getLocalResource("constructor/car-without-tags.yaml"));
+ assertEquals("12-XP-F4", car.getPlate());
+ List<Wheel> wheels = car.getWheels();
+ assertNotNull(wheels);
+ assertEquals(5, wheels.size());
+ }
+
+ public void testNullDescription() throws IOException {
+ Constructor constructor = new Constructor();
+ try {
+ constructor.addTypeDescription(null);
+ fail("Description is required.");
+ } catch (Exception e) {
+ assertEquals("TypeDescription is required.", e.getMessage());
+ }
+ }
+
+ public void testLoadClassNoRoot() throws IOException {
+ Constructor constructor = new Constructor();
+ TypeDescription carDescription = new TypeDescription(Car.class);
+ carDescription.setRoot(true);
+ constructor.addTypeDescription(carDescription);
+ Loader loader = new Loader(constructor);
+ Yaml yaml = new Yaml(loader);
+ Car car = (Car) yaml.load(Util.getLocalResource("constructor/car-no-root-class.yaml"));
+ assertEquals("12-XP-F4", car.getPlate());
+ List<Wheel> wheels = car.getWheels();
+ assertNotNull(wheels);
+ assertEquals(5, wheels.size());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/constructor/ConstructorMappingTest.java b/src/test/java/org/yaml/snakeyaml/constructor/ConstructorMappingTest.java new file mode 100644 index 00000000..3bdd6adb --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/constructor/ConstructorMappingTest.java @@ -0,0 +1,55 @@ +package org.yaml.snakeyaml.constructor;
+
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.TreeMap;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.composer.Composer;
+import org.yaml.snakeyaml.parser.Parser;
+import org.yaml.snakeyaml.parser.ParserImpl;
+import org.yaml.snakeyaml.reader.Reader;
+import org.yaml.snakeyaml.resolver.Resolver;
+
+public class ConstructorMappingTest extends TestCase {
+
+ @SuppressWarnings("unchecked")
+ public void testGetDefaultMap() {
+ String data = "{ one: 1, two: 2, three: 3 }";
+ Map<Object, Object> map = (Map<Object, Object>) construct(new CustomConstructor(), data);
+ assertNotNull(map);
+ assertTrue(map.getClass().toString(), map instanceof TreeMap);
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testGetLinkedList() {
+ String data = "{ one: 1, two: 2, three: 3 }";
+ Map<Object, Object> map = (Map<Object, Object>) construct(data);
+ assertNotNull(map);
+ assertTrue(map.getClass().toString(), map instanceof LinkedHashMap);
+ }
+
+ private Object construct(String data) {
+ return construct(new Constructor(), data);
+ }
+
+ private Object construct(Constructor constructor, String data) {
+ Reader reader = new Reader(data);
+ Parser parser = new ParserImpl(reader);
+ Resolver resolver = new Resolver();
+ Composer composer = new Composer(parser, resolver);
+ constructor.setComposer(composer);
+ return constructor.getSingleData();
+ }
+
+ class CustomConstructor extends Constructor {
+ @Override
+ protected Map<Object, Object> createDefaultMap() {
+ return new TreeMap<Object, Object>();
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/constructor/ConstructorSequenceTest.java b/src/test/java/org/yaml/snakeyaml/constructor/ConstructorSequenceTest.java new file mode 100644 index 00000000..5bc744a9 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/constructor/ConstructorSequenceTest.java @@ -0,0 +1,74 @@ +package org.yaml.snakeyaml.constructor;
+
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.composer.Composer;
+import org.yaml.snakeyaml.parser.Parser;
+import org.yaml.snakeyaml.parser.ParserImpl;
+import org.yaml.snakeyaml.reader.Reader;
+import org.yaml.snakeyaml.resolver.Resolver;
+
+public class ConstructorSequenceTest extends TestCase {
+
+ public void testGetList() {
+ String data = "[ 1, 2, 3 ]";
+ List<Object> list = construct(new CustomConstructor(), data);
+ assertNotNull(list);
+ assertTrue(list.getClass().toString(), list instanceof ArrayList);
+ }
+
+ public void testGetLinkedList() {
+ String data = "[ 1, 2, 3 ]";
+ List<Object> list = construct(data);
+ assertNotNull(list);
+ assertTrue(list.getClass().toString(), list instanceof LinkedList);
+ }
+
+ public void testDumpList() {
+ List<Integer> l = new ArrayList<Integer>(2);
+ l.add(1);
+ l.add(2);
+ Yaml yaml = new Yaml();
+ String result = yaml.dump(l);
+ assertEquals("[1, 2]\n", result);
+ }
+
+ public void testDumpListSameIntegers() {
+ List<Integer> l = new ArrayList<Integer>(2);
+ l.add(1);
+ l.add(1);
+ Yaml yaml = new Yaml();
+ String result = yaml.dump(l);
+ assertEquals("[1, 1]\n", result);
+ }
+
+ private List<Object> construct(String data) {
+ return construct(new Constructor(), data);
+ }
+
+ @SuppressWarnings("unchecked")
+ private List<Object> construct(Constructor constructor, String data) {
+ Reader reader = new Reader(data);
+ Parser parser = new ParserImpl(reader);
+ Resolver resolver = new Resolver();
+ Composer composer = new Composer(parser, resolver);
+ constructor.setComposer(composer);
+ List result = (List) constructor.getSingleData();
+ return result;
+ }
+
+ class CustomConstructor extends Constructor {
+ @Override
+ protected List<Object> createDefaultList(int initSize) {
+ return new ArrayList<Object>(initSize);
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/constructor/ConstructorTest.java b/src/test/java/org/yaml/snakeyaml/constructor/ConstructorTest.java new file mode 100644 index 00000000..9ee76be5 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/constructor/ConstructorTest.java @@ -0,0 +1,89 @@ +package org.yaml.snakeyaml.constructor;
+
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.TimeZone;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+
+public class ConstructorTest extends TestCase {
+
+ @SuppressWarnings("unchecked")
+ public void testMapOrder() {
+ String data = "one: zzz\ntwo: ccc\nthree: bbb\nfour: aaa";
+ Object map = construct(data);
+ assertNotNull(map);
+ assertTrue(map.getClass().toString(), map instanceof LinkedHashMap);
+ Map<String, String> m = (Map<String, String>) map;
+ assertEquals(4, m.keySet().size());
+ Iterator<String> iter = m.keySet().iterator();
+ assertEquals("one", iter.next());
+ assertEquals("two", iter.next());
+ assertEquals("three", iter.next());
+ assertEquals("four", iter.next());
+ }
+
+ /**
+ * create JavaBean
+ */
+ public void testGetBeanAssumeClass() {
+ String data = "--- !!org.yaml.snakeyaml.constructor.Person\nfirstName: Andrey\nage: 99";
+ Object obj = construct(data);
+ assertNotNull(obj);
+ assertTrue("Unexpected: " + obj.getClass().toString(), obj instanceof Person);
+ Person person = (Person) obj;
+ assertEquals("Andrey", person.getFirstName());
+ assertNull(person.getLastName());
+ assertEquals(99, person.getAge().intValue());
+ }
+
+ /**
+ * create instance using constructor arguments
+ */
+ public void testGetConstructorBean() {
+ String data = "--- !!org.yaml.snakeyaml.constructor.Person [ Andrey, Somov, 99 ]";
+ Object obj = construct(data);
+ assertNotNull(obj);
+ assertTrue(obj.getClass().toString(), obj instanceof Person);
+ Person person = (Person) obj;
+ assertEquals("Andrey", person.getFirstName());
+ assertEquals("Somov", person.getLastName());
+ assertEquals(99, person.getAge().intValue());
+ }
+
+ /**
+ * create instance using scalar argument
+ */
+ public void testGetConstructorFromScalar() {
+ String data = "--- !!org.yaml.snakeyaml.constructor.Person 'Somov'";
+ Object obj = construct(data);
+ assertNotNull(obj);
+ assertTrue(obj.getClass().toString(), obj instanceof Person);
+ Person person = (Person) obj;
+ assertNull("Andrey", person.getFirstName());
+ assertEquals("Somov", person.getLastName());
+ assertNull(person.getAge());
+ }
+
+ public void testJavaBeanLoad() {
+ java.util.Calendar cal = java.util.Calendar.getInstance(TimeZone.getTimeZone("UTC"));
+ cal.clear();
+ cal.set(1982, 5 - 1, 3); // Java's months are zero-based...
+
+ TestBean expected = new TestBean("Ola Bini", 24, cal.getTime());
+ assertEquals(
+ expected,
+ construct("--- !!org.yaml.snakeyaml.constructor.TestBean\nname: Ola Bini\nage: 24\nborn: 1982-05-03\n"));
+ }
+
+ private Object construct(String data) {
+ Yaml yaml = new Yaml();
+ return yaml.load(data);
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/constructor/ImplicitTagsTest.java b/src/test/java/org/yaml/snakeyaml/constructor/ImplicitTagsTest.java new file mode 100644 index 00000000..ade54ddc --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/constructor/ImplicitTagsTest.java @@ -0,0 +1,149 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.constructor;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Dumper;
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Loader;
+import org.yaml.snakeyaml.TypeDescription;
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.representer.Representer;
+
+public class ImplicitTagsTest extends TestCase {
+
+ public void testDefaultRepresenter() throws IOException {
+ CarWithWheel car1 = new CarWithWheel();
+ car1.setPlate("12-XP-F4");
+ Wheel wheel = new Wheel();
+ wheel.setId(2);
+ car1.setWheel(wheel);
+ Map<String, Integer> map = new HashMap<String, Integer>();
+ map.put("id", 3);
+ car1.setMap(map);
+ car1.setPart(new Wheel(4));
+ car1.setYear("2008");
+ String carYaml1 = new Yaml().dump(car1);
+ assertEquals(Util.getLocalResource("constructor/carwheel-without-tags.yaml"), carYaml1);
+ CarWithWheel car2 = (CarWithWheel) new Yaml().load(carYaml1);
+ String carYaml2 = new Yaml().dump(car2);
+ assertEquals(carYaml1, carYaml2);
+ }
+
+ public void testNoRootTag() throws IOException {
+ CarWithWheel car1 = new CarWithWheel();
+ car1.setPlate("12-XP-F4");
+ Wheel wheel = new Wheel();
+ wheel.setId(2);
+ car1.setWheel(wheel);
+ Map<String, Integer> map = new HashMap<String, Integer>();
+ map.put("id", 3);
+ car1.setMap(map);
+ car1.setYear("2008");
+ DumperOptions options = new DumperOptions();
+ options.setExplicitRoot("tag:yaml.org,2002:map");
+ String carYaml1 = new Yaml(options).dump(car1);
+ assertEquals(Util.getLocalResource("constructor/car-without-root-tag.yaml"), carYaml1);
+ //
+ Constructor contructor = new Constructor(CarWithWheel.class);
+ Loader loader = new Loader(contructor);
+ CarWithWheel car2 = (CarWithWheel) new Yaml(loader).load(carYaml1);
+ String carYaml2 = new Yaml(options).dump(car2);
+ assertEquals(carYaml1, carYaml2);
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testRootMap() throws IOException {
+ Map<Object, Object> car1 = new HashMap<Object, Object>();
+ car1.put("plate", "12-XP-F4");
+ Wheel wheel = new Wheel();
+ wheel.setId(2);
+ car1.put("wheel", wheel);
+ Map<String, Integer> map = new HashMap<String, Integer>();
+ map.put("id", 3);
+ car1.put("map", map);
+ String carYaml1 = new Yaml().dump(car1);
+ assertEquals(Util.getLocalResource("constructor/carwheel-root-map.yaml"), carYaml1);
+ Map<Object, Object> car2 = (Map<Object, Object>) new Yaml().load(carYaml1);
+ assertEquals(car1, car2);
+ assertEquals(carYaml1, new Yaml().dump(car2));
+ }
+
+ public void testLoadClassTag() throws IOException {
+ Constructor constructor = new Constructor();
+ constructor.addTypeDescription(new TypeDescription(Car.class, "!car"));
+ Loader loader = new Loader(constructor);
+ Yaml yaml = new Yaml(loader);
+ Car car = (Car) yaml.load(Util.getLocalResource("constructor/car-without-tags.yaml"));
+ assertEquals("12-XP-F4", car.getPlate());
+ List<Wheel> wheels = car.getWheels();
+ assertNotNull(wheels);
+ assertEquals(5, wheels.size());
+ //
+ String carYaml1 = new Yaml().dump(car);
+ assertTrue(carYaml1.startsWith("!!org.yaml.snakeyaml.constructor.Car"));
+ //
+ Representer representer = new Representer();
+ representer.addTypeDescription(new TypeDescription(Car.class, "!car"));
+ Dumper dumper = new Dumper(representer, new DumperOptions());
+ yaml = new Yaml(dumper);
+ String carYaml2 = yaml.dump(car);
+ assertEquals(Util.getLocalResource("constructor/car-without-tags.yaml"), carYaml2);
+ }
+
+ public static class CarWithWheel {
+ private String plate;
+ private String year;
+ private Wheel wheel;
+ private Object part;
+ private Map<String, Integer> map;
+
+ public String getPlate() {
+ return plate;
+ }
+
+ public void setPlate(String plate) {
+ this.plate = plate;
+ }
+
+ public Wheel getWheel() {
+ return wheel;
+ }
+
+ public void setWheel(Wheel wheel) {
+ this.wheel = wheel;
+ }
+
+ public Map<String, Integer> getMap() {
+ return map;
+ }
+
+ public void setMap(Map<String, Integer> map) {
+ this.map = map;
+ }
+
+ public Object getPart() {
+ return part;
+ }
+
+ public void setPart(Object part) {
+ this.part = part;
+ }
+
+ public String getYear() {
+ return year;
+ }
+
+ public void setYear(String year) {
+ this.year = year;
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/constructor/MyCar.java b/src/test/java/org/yaml/snakeyaml/constructor/MyCar.java new file mode 100644 index 00000000..c3107db1 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/constructor/MyCar.java @@ -0,0 +1,37 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.constructor;
+
+import java.util.Date;
+import java.util.Map;
+
+public class MyCar {
+ private String plate;
+ private Map<MyWheel, Date> wheels;
+ private Map<String, Integer> windows;
+
+ public String getPlate() {
+ return plate;
+ }
+
+ public void setPlate(String plate) {
+ this.plate = plate;
+ }
+
+ public Map<MyWheel, Date> getWheels() {
+ return wheels;
+ }
+
+ public void setWheels(Map<MyWheel, Date> wheels) {
+ this.wheels = wheels;
+ }
+
+ public Map<String, Integer> getWindows() {
+ return windows;
+ }
+
+ public void setWindows(Map<String, Integer> windows) {
+ this.windows = windows;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/constructor/MyWheel.java b/src/test/java/org/yaml/snakeyaml/constructor/MyWheel.java new file mode 100644 index 00000000..b99a8983 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/constructor/MyWheel.java @@ -0,0 +1,49 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.constructor;
+
+public class MyWheel {
+ private int id;
+ private String brand;
+
+ public MyWheel() {
+ brand = "Pirelli";
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ @Override
+ public String toString() {
+ return "Wheel id=" + id;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof MyWheel) {
+ MyWheel wheel = (MyWheel) obj;
+ return id == wheel.getId();
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return new Integer(id).hashCode();
+ }
+
+ public String getBrand() {
+ return brand;
+ }
+
+ public void setBrand(String brand) {
+ this.brand = brand;
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/constructor/Parent1.java b/src/test/java/org/yaml/snakeyaml/constructor/Parent1.java new file mode 100644 index 00000000..c3652f3f --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/constructor/Parent1.java @@ -0,0 +1,26 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.constructor;
+
+public class Parent1 {
+ private String id;
+ private Child1 child;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public Child1 getChild() {
+ return child;
+ }
+
+ public void setChild(Child1 child) {
+ this.child = child;
+ }
+
+}
\ No newline at end of file diff --git a/src/test/java/org/yaml/snakeyaml/constructor/Person.java b/src/test/java/org/yaml/snakeyaml/constructor/Person.java new file mode 100644 index 00000000..0067f4b4 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/constructor/Person.java @@ -0,0 +1,51 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.constructor;
+
+/**
+ * Test JavaBean
+ */
+public class Person {
+ private String firstName;
+ private String lastName;
+ private Integer age;
+
+ public Person(String firstName, String lastName, Integer age) {
+ this.firstName = firstName;
+ this.lastName = lastName;
+ this.age = age;
+ }
+
+ public Person() {
+ }
+
+ public Person(String lastName) {
+ this.lastName = lastName;
+ }
+
+ public String getFirstName() {
+ return firstName;
+ }
+
+ public void setFirstName(String firstName) {
+ this.firstName = firstName;
+ }
+
+ public String getLastName() {
+ return lastName;
+ }
+
+ public void setLastName(String lastName) {
+ this.lastName = lastName;
+ }
+
+ public Integer getAge() {
+ return age;
+ }
+
+ public void setAge(Integer age) {
+ this.age = age;
+ }
+
+}
diff --git a/src/test/java/org/yaml/snakeyaml/constructor/SafeConstructorTest.java b/src/test/java/org/yaml/snakeyaml/constructor/SafeConstructorTest.java new file mode 100644 index 00000000..5b947a47 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/constructor/SafeConstructorTest.java @@ -0,0 +1,39 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.constructor; + +import junit.framework.TestCase; + +import org.yaml.snakeyaml.Loader; +import org.yaml.snakeyaml.Yaml; + +public class SafeConstructorTest extends TestCase { + + public void testConstructFloat() { + Yaml yaml = new Yaml(); + assertEquals(3.1416, yaml.load("+3.1416")); + assertEquals(Double.POSITIVE_INFINITY, yaml.load("+.inf")); + assertEquals(Double.POSITIVE_INFINITY, yaml.load(".inf")); + assertEquals(Double.NEGATIVE_INFINITY, yaml.load("-.inf")); + } + + public void testSafeConstruct() { + Yaml yaml = new Yaml(new Loader(new SafeConstructor())); + assertEquals(3.1416, yaml.load("+3.1416")); + } + + public void testSafeConstructJavaBean() { + Yaml yaml = new Yaml(new Loader(new SafeConstructor())); + String data = "--- !!org.yaml.snakeyaml.constructor.Person\nfirstName: Andrey\nage: 99"; + try { + yaml.load(data); + fail("JavaBeans cannot be created by SafeConstructor."); + } catch (ConstructorException e) { + assertTrue(e + .getMessage() + .contains( + "could not determine a constructor for the tag tag:yaml.org,2002:org.yaml.snakeyaml.constructor.Person")); + } + } +} diff --git a/src/test/java/org/yaml/snakeyaml/constructor/TestBean.java b/src/test/java/org/yaml/snakeyaml/constructor/TestBean.java new file mode 100644 index 00000000..47ef11ca --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/constructor/TestBean.java @@ -0,0 +1,71 @@ +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.constructor; + +import java.util.Date; + +/** + * @author <a href="mailto:ola.bini@ki.se">Ola Bini</a> + */ +public class TestBean { + private String name; + private int age; + private Date born; + + public TestBean() { + } + + public TestBean(final String name, final int age, final Date born) { + this.name = name; + this.age = age; + this.born = born; + } + + public String getName() { + return this.name; + } + + public int getAge() { + return age; + } + + public Date getBorn() { + return born; + } + + public void setName(final String name) { + this.name = name; + } + + public void setAge(final int age) { + this.age = age; + } + + public void setBorn(final Date born) { + this.born = born; + } + + public boolean equals(final Object other) { + boolean ret = this == other; + if (!ret && other instanceof TestBean) { + TestBean o = (TestBean) other; + ret = this.name == null ? o.name == null : this.name.equals(o.name) + && this.age == o.age && this.born == null ? o.born == null : this.born + .equals(o.born); + } + return ret; + } + + public int hashCode() { + int val = 3; + val += 3 * (name == null ? 0 : name.hashCode()); + val += 3 * age; + val += 3 * (born == null ? 0 : born.hashCode()); + return val; + } + + public String toString() { + return "#<org.jvyaml.TestBean name=\"" + name + "\" age=" + age + " born=\"" + born + "\">"; + } +} diff --git a/src/test/java/org/yaml/snakeyaml/constructor/TestBean1.java b/src/test/java/org/yaml/snakeyaml/constructor/TestBean1.java new file mode 100644 index 00000000..18ef9e0c --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/constructor/TestBean1.java @@ -0,0 +1,192 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.constructor;
+
+import java.math.BigInteger;
+import java.util.Date;
+
+public class TestBean1 {
+ private String text;
+ private String id;
+ private Byte byteClass;
+ private byte bytePrimitive;
+ private Short shortClass;
+ private short shortPrimitive;
+ private Integer integer;
+ private int intPrimitive;
+ private Long longClass;
+ private long longPrimitive;
+ private Boolean booleanClass;
+ private boolean booleanPrimitive;
+ private Character charClass;
+ private char charPrimitive;
+ private BigInteger bigInteger;
+ private Float floatClass;
+ private float floatPrimitive;
+ private Double doubleClass;
+ private double doublePrimitive;
+ private Date date;
+ public String publicField;
+ static public Integer staticInteger;
+
+ public String getText() {
+ return text;
+ }
+
+ public void setText(String text) {
+ this.text = text;
+ }
+
+ public Integer getInteger() {
+ return integer;
+ }
+
+ public void setInteger(Integer integer) {
+ this.integer = integer;
+ }
+
+ public int getIntPrimitive() {
+ return intPrimitive;
+ }
+
+ public void setIntPrimitive(int intPrimitive) {
+ this.intPrimitive = intPrimitive;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public Byte getByteClass() {
+ return byteClass;
+ }
+
+ public void setByteClass(Byte byteClass) {
+ this.byteClass = byteClass;
+ }
+
+ public byte getBytePrimitive() {
+ return bytePrimitive;
+ }
+
+ public void setBytePrimitive(byte bytePrimitive) {
+ this.bytePrimitive = bytePrimitive;
+ }
+
+ public Short getShortClass() {
+ return shortClass;
+ }
+
+ public void setShortClass(Short shortClass) {
+ this.shortClass = shortClass;
+ }
+
+ public short getShortPrimitive() {
+ return shortPrimitive;
+ }
+
+ public void setShortPrimitive(short shortPrimitive) {
+ this.shortPrimitive = shortPrimitive;
+ }
+
+ public Long getLongClass() {
+ return longClass;
+ }
+
+ public void setLongClass(Long longClass) {
+ this.longClass = longClass;
+ }
+
+ public long getLongPrimitive() {
+ return longPrimitive;
+ }
+
+ public void setLongPrimitive(long longPrimitive) {
+ this.longPrimitive = longPrimitive;
+ }
+
+ public Boolean getBooleanClass() {
+ return booleanClass;
+ }
+
+ public void setBooleanClass(Boolean booleanClass) {
+ this.booleanClass = booleanClass;
+ }
+
+ public boolean isBooleanPrimitive() {
+ return booleanPrimitive;
+ }
+
+ public void setBooleanPrimitive(boolean booleanPrimitive) {
+ this.booleanPrimitive = booleanPrimitive;
+ }
+
+ public Character getCharClass() {
+ return charClass;
+ }
+
+ public void setCharClass(Character charClass) {
+ this.charClass = charClass;
+ }
+
+ public char getCharPrimitive() {
+ return charPrimitive;
+ }
+
+ public void setCharPrimitive(char charPrimitive) {
+ this.charPrimitive = charPrimitive;
+ }
+
+ public BigInteger getBigInteger() {
+ return bigInteger;
+ }
+
+ public void setBigInteger(BigInteger bigInteger) {
+ this.bigInteger = bigInteger;
+ }
+
+ public Float getFloatClass() {
+ return floatClass;
+ }
+
+ public void setFloatClass(Float floatClass) {
+ this.floatClass = floatClass;
+ }
+
+ public float getFloatPrimitive() {
+ return floatPrimitive;
+ }
+
+ public void setFloatPrimitive(float floatPrimitive) {
+ this.floatPrimitive = floatPrimitive;
+ }
+
+ public Double getDoubleClass() {
+ return doubleClass;
+ }
+
+ public void setDoubleClass(Double doubleClass) {
+ this.doubleClass = doubleClass;
+ }
+
+ public double getDoublePrimitive() {
+ return doublePrimitive;
+ }
+
+ public void setDoublePrimitive(double doublePrimitive) {
+ this.doublePrimitive = doublePrimitive;
+ }
+
+ public Date getDate() {
+ return date;
+ }
+
+ public void setDate(Date date) {
+ this.date = date;
+ }
+}
\ No newline at end of file diff --git a/src/test/java/org/yaml/snakeyaml/constructor/TypeSafeCollectionsTest.java b/src/test/java/org/yaml/snakeyaml/constructor/TypeSafeCollectionsTest.java new file mode 100644 index 00000000..3909325f --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/constructor/TypeSafeCollectionsTest.java @@ -0,0 +1,82 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.constructor;
+
+import java.io.IOException;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Dumper;
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Loader;
+import org.yaml.snakeyaml.TypeDescription;
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.representer.Representer;
+
+public class TypeSafeCollectionsTest extends TestCase {
+
+ public void testTypeSafeList() throws IOException {
+ Constructor constructor = new Constructor(Car.class);
+ TypeDescription carDescription = new TypeDescription(Car.class);
+ carDescription.putListPropertyType("wheels", Wheel.class);
+ constructor.addTypeDescription(carDescription);
+ Loader loader = new Loader(constructor);
+ Yaml yaml = new Yaml(loader);
+ Car car = (Car) yaml.load(Util.getLocalResource("constructor/car-no-root-class.yaml"));
+ assertEquals("12-XP-F4", car.getPlate());
+ List<Wheel> wheels = car.getWheels();
+ assertNotNull(wheels);
+ assertEquals(5, wheels.size());
+ for (Wheel wheel : wheels) {
+ assertTrue(wheel.getId() > 0);
+ }
+ }
+
+ public void testTypeSafeMap() throws IOException {
+ Constructor constructor = new Constructor(MyCar.class);
+ TypeDescription carDescription = new TypeDescription(MyCar.class);
+ carDescription.putMapPropertyType("wheels", MyWheel.class, Object.class);
+ constructor.addTypeDescription(carDescription);
+ Loader loader = new Loader(constructor);
+ Yaml yaml = new Yaml(loader);
+ MyCar car = (MyCar) yaml.load(Util
+ .getLocalResource("constructor/car-no-root-class-map.yaml"));
+ assertEquals("00-FF-Q2", car.getPlate());
+ Map<MyWheel, Date> wheels = car.getWheels();
+ assertNotNull(wheels);
+ assertEquals(5, wheels.size());
+ for (MyWheel wheel : wheels.keySet()) {
+ assertTrue(wheel.getId() > 0);
+ Date date = wheels.get(wheel);
+ long time = date.getTime();
+ assertTrue("It must be midnight.", time % 10000 == 0);
+ }
+ }
+
+ public void test1() throws IOException {
+ Map<MyWheel, Date> wheels = new HashMap<MyWheel, Date>();
+ for (int i = 1; i < 6; i++) {
+ MyWheel mw = new MyWheel();
+ mw.setId(i);
+ if (i == 2) {
+ mw.setBrand("Michel");
+ }
+ wheels.put(mw, new Date());
+ }
+ MyCar c = new MyCar();
+ c.setPlate("00-FF-Q2");
+ c.setWheels(wheels);
+ Representer representer = new Representer();
+ representer.addTypeDescription(new TypeDescription(MyWheel.class, "tag:yaml.org,2002:map"));
+ Dumper dumper = new Dumper(representer, new DumperOptions());
+ Yaml yaml = new Yaml(dumper);
+ String output = yaml.dump(c);
+ System.out.println(output);
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/constructor/Wheel.java b/src/test/java/org/yaml/snakeyaml/constructor/Wheel.java new file mode 100644 index 00000000..07e66f80 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/constructor/Wheel.java @@ -0,0 +1,44 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.constructor;
+
+public class Wheel {
+ private int id;
+
+ public Wheel(int id) {
+ this.id = id;
+ }
+
+ public Wheel() {
+ this(0);
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ @Override
+ public String toString() {
+ return "Wheel id=" + id;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof Wheel) {
+ Wheel wheel = (Wheel) obj;
+ return id == wheel.getId();
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return new Integer(id).hashCode();
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/emitter/EmitterTest.java b/src/test/java/org/yaml/snakeyaml/emitter/EmitterTest.java new file mode 100644 index 00000000..1314fbb9 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/emitter/EmitterTest.java @@ -0,0 +1,82 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.emitter;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.DumperOptions.DefaultScalarStyle;
+
+public class EmitterTest extends TestCase {
+
+ public void testWriteFolded() {
+ DumperOptions options = new DumperOptions();
+ options.setDefaultStyle(DefaultScalarStyle.FOLDED);
+ String folded = "0123456789 0123456789\n0123456789 0123456789";
+ Map<String, String> map = new LinkedHashMap<String, String>();
+ map.put("aaa", folded);
+ map.put("bbb", "\nbla-bla\n");
+ Yaml yaml = new Yaml(options);
+ String output = yaml.dump(map);
+ String etalon = "\"aaa\": >-\n 0123456789 0123456789\n\n 0123456789 0123456789\n\"bbb\": >2\n\n bla-bla\n";
+ assertEquals(etalon, output);
+ }
+
+ public void testWriteLiteral() {
+ DumperOptions options = new DumperOptions();
+ options.setDefaultStyle(DefaultScalarStyle.LITERAL);
+ String folded = "0123456789 0123456789 0123456789 0123456789";
+ Map<String, String> map = new LinkedHashMap<String, String>();
+ map.put("aaa", folded);
+ map.put("bbb", "\nbla-bla\n");
+ Yaml yaml = new Yaml(options);
+ String output = yaml.dump(map);
+ System.out.println(output);
+ String etalon = "\"aaa\": |-\n 0123456789 0123456789 0123456789 0123456789\n\"bbb\": |2\n\n bla-bla\n";
+ assertEquals(etalon, output);
+ }
+
+ public void testWritePlain() {
+ DumperOptions options = new DumperOptions();
+ options.setDefaultStyle(DefaultScalarStyle.PLAIN);
+ String folded = "0123456789 0123456789\n0123456789 0123456789";
+ Map<String, String> map = new LinkedHashMap<String, String>();
+ map.put("aaa", folded);
+ map.put("bbb", "\nbla-bla");
+ Yaml yaml = new Yaml(options);
+ String output = yaml.dump(map);
+ String etalon = "{aaa: '0123456789 0123456789\n\n 0123456789 0123456789', bbb: '\n\n bla-bla'}\n";
+ assertEquals(etalon, output);
+ }
+
+ public void testWriteSingleQuoted() {
+ DumperOptions options = new DumperOptions();
+ options.setDefaultStyle(DefaultScalarStyle.SINGLE_QUOTED);
+ String folded = "0123456789 0123456789\n0123456789 0123456789";
+ Map<String, String> map = new LinkedHashMap<String, String>();
+ map.put("aaa", folded);
+ map.put("bbb", "\nbla-bla");
+ Yaml yaml = new Yaml(options);
+ String output = yaml.dump(map);
+ String etalon = "'aaa': '0123456789 0123456789\n\n 0123456789 0123456789'\n'bbb': '\n\n bla-bla'\n";
+ assertEquals(etalon, output);
+ }
+
+ public void testWriteDoubleQuoted() {
+ DumperOptions options = new DumperOptions();
+ options.setDefaultStyle(DefaultScalarStyle.DOUBLE_QUOTED);
+ String folded = "0123456789 0123456789\n0123456789 0123456789";
+ Map<String, String> map = new LinkedHashMap<String, String>();
+ map.put("aaa", folded);
+ map.put("bbb", "\nbla-bla");
+ Yaml yaml = new Yaml(options);
+ String output = yaml.dump(map);
+ String etalon = "\"aaa\": \"0123456789 0123456789\\n0123456789 0123456789\"\n\"bbb\": \"\\nbla-bla\"\n";
+ assertEquals(etalon, output);
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/emitter/EventConstructor.java b/src/test/java/org/yaml/snakeyaml/emitter/EventConstructor.java new file mode 100644 index 00000000..7309e1ad --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/emitter/EventConstructor.java @@ -0,0 +1,106 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.emitter;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.yaml.snakeyaml.constructor.Construct;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.events.AliasEvent;
+import org.yaml.snakeyaml.events.DocumentEndEvent;
+import org.yaml.snakeyaml.events.DocumentStartEvent;
+import org.yaml.snakeyaml.events.Event;
+import org.yaml.snakeyaml.events.MappingEndEvent;
+import org.yaml.snakeyaml.events.MappingStartEvent;
+import org.yaml.snakeyaml.events.ScalarEvent;
+import org.yaml.snakeyaml.events.SequenceEndEvent;
+import org.yaml.snakeyaml.events.SequenceStartEvent;
+import org.yaml.snakeyaml.events.StreamEndEvent;
+import org.yaml.snakeyaml.events.StreamStartEvent;
+import org.yaml.snakeyaml.nodes.MappingNode;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.ScalarNode;
+
+public class EventConstructor extends Constructor {
+
+ public EventConstructor() {
+ this.yamlConstructors.put(null, new ConstructEvent());
+ }
+
+ private class ConstructEvent implements Construct {
+
+ @SuppressWarnings("unchecked")
+ public Object construct(Node node) {
+ Map mapping;
+ if (node instanceof ScalarNode) {
+ mapping = new HashMap();
+ } else {
+ mapping = constructMapping((MappingNode) node);
+ }
+ String className = node.getTag().substring(1) + "Event";
+ Event value;
+ if (className.equals("AliasEvent")) {
+ value = new AliasEvent((String) mapping.get("anchor"), null, null);
+ } else if (className.equals("ScalarEvent")) {
+ String tag = (String) mapping.get("tag");
+ String v = (String) mapping.get("value");
+ if (v == null) {
+ v = "";
+ }
+ List implicitList = (List) mapping.get("implicit");
+ boolean implicit[];
+ if (implicitList == null) {
+ implicit = new boolean[] { false, true };
+ } else {
+ implicit = new boolean[2];
+ implicit[0] = (Boolean) implicitList.get(0);
+ implicit[1] = (Boolean) implicitList.get(1);
+ }
+ value = new ScalarEvent((String) mapping.get("anchor"), tag, implicit, v, null,
+ null, null);
+ } else if (className.equals("SequenceStartEvent")) {
+ String tag = (String) mapping.get("tag");
+ Boolean implicit = (Boolean) mapping.get("implicit");
+ if (implicit == null) {
+ implicit = true;
+ }
+ value = new SequenceStartEvent((String) mapping.get("anchor"), tag, implicit, null,
+ null, false);
+ } else if (className.equals("MappingStartEvent")) {
+ String tag = (String) mapping.get("tag");
+ Boolean implicit = (Boolean) mapping.get("implicit");
+ if (implicit == null) {
+ implicit = true;
+ }
+ value = new MappingStartEvent((String) mapping.get("anchor"), tag, implicit, null,
+ null, false);
+ } else if (className.equals("DocumentEndEvent")) {
+ value = new DocumentEndEvent(null, null, false);
+ } else if (className.equals("DocumentStartEvent")) {
+ Map<String, String> tags = (Map<String, String>) mapping.get("tags");
+ List<Integer> versionList = (List<Integer>) mapping.get("version");
+ Integer[] version = null;
+ if (versionList != null) {
+ version = new Integer[2];
+ version[0] = versionList.get(0).intValue();
+ version[1] = versionList.get(1).intValue();
+ }
+ value = new DocumentStartEvent(null, null, false, version, tags);
+ } else if (className.equals("MappingEndEvent")) {
+ value = new MappingEndEvent(null, null);
+ } else if (className.equals("SequenceEndEvent")) {
+ value = new SequenceEndEvent(null, null);
+ } else if (className.equals("StreamEndEvent")) {
+ value = new StreamEndEvent(null, null);
+ } else if (className.equals("StreamStartEvent")) {
+ value = new StreamStartEvent(null, null);
+ } else {
+ throw new UnsupportedOperationException();
+ }
+ return value;
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/emitter/EventsLoader.java b/src/test/java/org/yaml/snakeyaml/emitter/EventsLoader.java new file mode 100644 index 00000000..567f5290 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/emitter/EventsLoader.java @@ -0,0 +1,13 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.emitter;
+
+import org.yaml.snakeyaml.Loader;
+
+public class EventsLoader extends Loader {
+
+ public EventsLoader() {
+ super(new EventConstructor());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/error/MarkTest.java b/src/test/java/org/yaml/snakeyaml/error/MarkTest.java new file mode 100644 index 00000000..40a88a74 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/error/MarkTest.java @@ -0,0 +1,25 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.error;
+
+import junit.framework.TestCase;
+
+public class MarkTest extends TestCase {
+
+ public void testGet_snippet() {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ assertEquals(" *The first line.\n ^", mark.get_snippet());
+ mark = new Mark("test1", 9, 0, 0, "The first*line.\nThe last line.", 9);
+ assertEquals(" The first*line.\n ^", mark.get_snippet());
+ }
+
+ public void testToString() {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ String[] lines = mark.toString().split("\n");
+ assertEquals(" in \"test1\", line 0, column 0:", lines[0]);
+ assertEquals("*The first line.", lines[1].trim());
+ assertEquals("^", lines[2].trim());
+ }
+
+}
diff --git a/src/test/java/org/yaml/snakeyaml/error/MarkedYAMLExceptionTest.java b/src/test/java/org/yaml/snakeyaml/error/MarkedYAMLExceptionTest.java new file mode 100644 index 00000000..dc6991cb --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/error/MarkedYAMLExceptionTest.java @@ -0,0 +1,27 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.error;
+
+import junit.framework.TestCase;
+
+public class MarkedYAMLExceptionTest extends TestCase {
+
+ public void testToString1() {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ MarkedYAMLException exception = new MarkedYAMLException(null, null, "Error happened", mark);
+ assertTrue(exception.toString().contains("Error happened"));
+ assertTrue(exception.toString().contains("The first line"));
+ assertTrue(exception.toString().contains("\"test1\""));
+ }
+
+ public void testToString2() {
+ Mark mark = new Mark("search", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ MarkedYAMLException exception = new MarkedYAMLException("See http://www.google.com", mark,
+ "Error2 happened", mark);
+ assertTrue(exception.toString().contains("Error2 happened"));
+ assertTrue(exception.toString().contains("The first line"));
+ assertTrue(exception.toString().contains("\"search\""));
+ }
+
+}
diff --git a/src/test/java/org/yaml/snakeyaml/events/ScalarEventTest.java b/src/test/java/org/yaml/snakeyaml/events/ScalarEventTest.java new file mode 100644 index 00000000..2406ce03 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/events/ScalarEventTest.java @@ -0,0 +1,27 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.events;
+
+import junit.framework.TestCase;
+
+public class ScalarEventTest extends TestCase {
+
+ public void testToString() {
+ boolean[] implicit = new boolean[2];
+ implicit[0] = true;
+ implicit[1] = true;
+ ScalarEvent event = new ScalarEvent("a2", "str", implicit, "text", null, null, '"');
+ assertEquals(
+ "<org.yaml.snakeyaml.events.ScalarEvent(anchor=a2, tag=str, implicit=[true, true], value=text)>",
+ event.toString());
+ }
+
+ public void testNotEqual() {
+ boolean[] implicit = new boolean[2];
+ implicit[0] = true;
+ implicit[1] = true;
+ ScalarEvent event = new ScalarEvent("a2", "str", implicit, "text", null, null, '"');
+ assertFalse(event.equals(event.toString()));
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/introspector/MethodPropertyTest.java b/src/test/java/org/yaml/snakeyaml/introspector/MethodPropertyTest.java new file mode 100644 index 00000000..1bcb7dcf --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/introspector/MethodPropertyTest.java @@ -0,0 +1,22 @@ +package org.yaml.snakeyaml.introspector;
+
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.constructor.TestBean1;
+
+public class MethodPropertyTest extends TestCase {
+
+ public void testToString() throws IntrospectionException {
+ for (PropertyDescriptor property : Introspector.getBeanInfo(TestBean1.class)
+ .getPropertyDescriptors()) {
+ if (property.getName().equals("text")) {
+ MethodProperty prop = new MethodProperty(property);
+ assertEquals("text of class java.lang.String", prop.toString());
+ }
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/nodes/NodeTest.java b/src/test/java/org/yaml/snakeyaml/nodes/NodeTest.java new file mode 100644 index 00000000..eb9d817c --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/nodes/NodeTest.java @@ -0,0 +1,28 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.nodes;
+
+import junit.framework.TestCase;
+
+public class NodeTest extends TestCase {
+
+ public void testNode() {
+ try {
+ new ScalarNode("!foo", null, null, null, '"');
+ fail("Value must be required.");
+ } catch (Exception e) {
+ assertEquals("value in a Node is required.", e.getMessage());
+ }
+ }
+
+ public void testSetTag() {
+ try {
+ ScalarNode node = new ScalarNode("!foo", "Value1", null, null, '"');
+ node.setTag(null);
+ fail("Value must be required.");
+ } catch (Exception e) {
+ assertEquals("tag in a Node is required.", e.getMessage());
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/nodes/ScalarNodeTest.java b/src/test/java/org/yaml/snakeyaml/nodes/ScalarNodeTest.java new file mode 100644 index 00000000..c5eb45df --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/nodes/ScalarNodeTest.java @@ -0,0 +1,26 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.nodes;
+
+import junit.framework.TestCase;
+
+public class ScalarNodeTest extends TestCase {
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ public void testGetNodeId() {
+ Node node = new ScalarNode("str", "text", null, null, '>');
+ assertEquals(NodeId.scalar, node.getNodeId());
+ }
+
+ public void testToString() {
+ Node node = new ScalarNode("str", "text", null, null, '>');
+ assertTrue(node.toString().contains("ScalarNode"));
+ assertTrue(node.toString().contains("tag="));
+ assertTrue(node.toString().contains("value="));
+ }
+
+}
diff --git a/src/test/java/org/yaml/snakeyaml/nodes/SequenceNodeTest.java b/src/test/java/org/yaml/snakeyaml/nodes/SequenceNodeTest.java new file mode 100644 index 00000000..d8a08afb --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/nodes/SequenceNodeTest.java @@ -0,0 +1,16 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.nodes;
+
+import java.util.ArrayList;
+
+import junit.framework.TestCase;
+
+public class SequenceNodeTest extends TestCase {
+
+ public void testGetNodeId() {
+ SequenceNode node = new SequenceNode("!foo", new ArrayList<Node>(), null, null, true);
+ assertEquals(NodeId.sequence, node.getNodeId());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/parser/ParserImplTest.java b/src/test/java/org/yaml/snakeyaml/parser/ParserImplTest.java new file mode 100644 index 00000000..9e3f624c --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/parser/ParserImplTest.java @@ -0,0 +1,88 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.parser;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.error.Mark;
+import org.yaml.snakeyaml.events.DocumentEndEvent;
+import org.yaml.snakeyaml.events.DocumentStartEvent;
+import org.yaml.snakeyaml.events.Event;
+import org.yaml.snakeyaml.events.MappingEndEvent;
+import org.yaml.snakeyaml.events.MappingStartEvent;
+import org.yaml.snakeyaml.events.ScalarEvent;
+import org.yaml.snakeyaml.events.SequenceEndEvent;
+import org.yaml.snakeyaml.events.SequenceStartEvent;
+import org.yaml.snakeyaml.events.StreamEndEvent;
+import org.yaml.snakeyaml.events.StreamStartEvent;
+import org.yaml.snakeyaml.reader.Reader;
+
+public class ParserImplTest extends TestCase {
+
+ public void testGetEvent() {
+ String data = "string: abcd";
+ Reader reader = new Reader(data);
+ Parser parser = new ParserImpl(reader);
+ Mark dummyMark = new Mark("dummy", 0, 0, 0, "", 0);
+ LinkedList<Event> etalonEvents = new LinkedList<Event>();
+ etalonEvents.add(new StreamStartEvent(dummyMark, dummyMark));
+ etalonEvents.add(new DocumentStartEvent(dummyMark, dummyMark, false, null, null));
+ etalonEvents.add(new MappingStartEvent(null, null, true, dummyMark, dummyMark,
+ Boolean.FALSE));
+ boolean[] implicit = { true, false };
+ etalonEvents.add(new ScalarEvent(null, null, implicit, "string", dummyMark, dummyMark,
+ (char) 0));
+ etalonEvents.add(new ScalarEvent(null, null, implicit, "abcd", dummyMark, dummyMark,
+ (char) 0));
+ etalonEvents.add(new MappingEndEvent(dummyMark, dummyMark));
+ etalonEvents.add(new DocumentEndEvent(dummyMark, dummyMark, false));
+ etalonEvents.add(new StreamEndEvent(dummyMark, dummyMark));
+ while (parser.checkEvent(new ArrayList<Class<? extends Event>>())) {
+ Event event = parser.getEvent();
+ if (etalonEvents.isEmpty()) {
+ fail("unexpected event: " + event);
+ }
+ assertEquals(etalonEvents.removeFirst(), event);
+ // System.out.println(event);
+ }
+ assertFalse("Must contain no more events: " + parser.getEvent(), parser
+ .checkEvent(new ArrayList<Class<? extends Event>>()));
+ }
+
+ public void testGetEvent2() {
+ String data = "american:\n - Boston Red Sox";
+ Reader reader = new Reader(data);
+ Parser parser = new ParserImpl(reader);
+ Mark dummyMark = new Mark("dummy", 0, 0, 0, "", 0);
+ LinkedList<Event> etalonEvents = new LinkedList<Event>();
+ etalonEvents.add(new StreamStartEvent(dummyMark, dummyMark));
+ etalonEvents.add(new DocumentStartEvent(dummyMark, dummyMark, false, null, null));
+ etalonEvents
+ .add(new MappingStartEvent(null, null, true, dummyMark, dummyMark, Boolean.TRUE));
+ boolean[] implicit = { true, false };
+ etalonEvents.add(new ScalarEvent(null, null, implicit, "american", dummyMark, dummyMark,
+ (char) 0));
+ etalonEvents.add(new SequenceStartEvent(null, null, true, dummyMark, dummyMark,
+ Boolean.FALSE));
+ etalonEvents.add(new ScalarEvent(null, null, implicit, "Boston Red Sox", dummyMark,
+ dummyMark, (char) 0));
+ etalonEvents.add(new SequenceEndEvent(dummyMark, dummyMark));
+ etalonEvents.add(new MappingEndEvent(dummyMark, dummyMark));
+ etalonEvents.add(new DocumentEndEvent(dummyMark, dummyMark, false));
+ etalonEvents.add(new StreamEndEvent(dummyMark, dummyMark));
+ while (parser.checkEvent(new ArrayList<Class<? extends Event>>())) {
+ Event event = parser.getEvent();
+ if (etalonEvents.isEmpty()) {
+ fail("unexpected event: " + event);
+ }
+ assertEquals(etalonEvents.removeFirst(), event);
+ // System.out.println(event);
+ }
+ assertFalse("Must contain no more events: " + parser.getEvent(), parser
+ .checkEvent(new ArrayList<Class<? extends Event>>()));
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/reader/IoReaderTest.java b/src/test/java/org/yaml/snakeyaml/reader/IoReaderTest.java new file mode 100644 index 00000000..8a69beec --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/reader/IoReaderTest.java @@ -0,0 +1,25 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.reader;
+
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+
+public class IoReaderTest extends TestCase {
+
+ @SuppressWarnings("unchecked")
+ public void testCheckPrintable() throws IOException {
+ Yaml yaml = new Yaml();
+ java.io.Reader reader = null;
+ reader = new FileReader("src/test/resources/specification/example2_1.yaml");
+ List<String> list = (List<String>) yaml.load(reader);
+ reader.close();
+ assertEquals(3, list.size());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/reader/ReaderBomTest.java b/src/test/java/org/yaml/snakeyaml/reader/ReaderBomTest.java new file mode 100644 index 00000000..b5d6578c --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/reader/ReaderBomTest.java @@ -0,0 +1,101 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.reader;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringReader;
+import java.nio.charset.Charset;
+
+import junit.framework.TestCase;
+
+public class ReaderBomTest extends TestCase {
+
+ public void testReader() throws IOException {
+ java.io.Reader input = new StringReader("test");
+ Reader reader = new Reader(input);
+ assertEquals('t', reader.peek());
+ reader.forward(1);
+ assertEquals('e', reader.peek());
+ reader.forward(1);
+ assertEquals('s', reader.peek());
+ reader.forward(1);
+ assertEquals('t', reader.peek());
+ reader.forward(1);
+ assertEquals('\u0000', reader.peek());
+ }
+
+ public void testNoBom() throws IOException {
+ byte[] data = "test".getBytes("UTF-8");
+ ByteArrayInputStream input = new ByteArrayInputStream(data);
+ java.io.Reader r = new UnicodeReader(input);
+ Reader reader = new Reader(r);
+ assertEquals('t', reader.peek());
+ assertEquals(Charset.forName("UTF-8"), reader.getEncoding());
+ reader.forward(1);
+ assertEquals('e', reader.peek());
+ reader.forward(1);
+ assertEquals('s', reader.peek());
+ reader.forward(1);
+ assertEquals('t', reader.peek());
+ reader.forward(1);
+ assertEquals('\u0000', reader.peek());
+ r.close();
+ }
+
+ public void testUtf8Bom() throws IOException {
+ File file = new File("src/test/resources/reader/utf-8.txt");
+ assertTrue("Test file not found: " + file.getAbsolutePath(), file.exists());
+ InputStream input = new FileInputStream(file);
+ Reader reader = new Reader(new UnicodeReader(input));
+ assertEquals('t', reader.peek());
+ reader.forward(1);
+ assertEquals('e', reader.peek());
+ reader.forward(1);
+ assertEquals('s', reader.peek());
+ reader.forward(1);
+ assertEquals('t', reader.peek());
+ reader.forward(1);
+ assertEquals('\u0000', reader.peek());
+ assertEquals(Charset.forName("UTF-8"), reader.getEncoding());
+ }
+
+ public void testUnicodeLeBom() throws IOException {
+ File file = new File("src/test/resources/reader/unicode-16le.txt");
+ assertTrue("Test file not found: " + file.getAbsolutePath(), file.exists());
+ InputStream input = new FileInputStream(file);
+ Reader reader = new Reader(new UnicodeReader(input));
+ assertEquals('t', reader.peek());
+ reader.forward(1);
+ assertEquals('e', reader.peek());
+ reader.forward(1);
+ assertEquals('s', reader.peek());
+ reader.forward(1);
+ assertEquals('t', reader.peek());
+ reader.forward(1);
+ assertEquals('\u0000', reader.peek());
+ assertEquals(Charset.forName("UTF-16LE"), reader.getEncoding());
+ }
+
+ public void testUnicodeBeBom() throws IOException {
+ File file = new File("src/test/resources/reader/unicode-16be.txt");
+ assertTrue("Test file not found: " + file.getAbsolutePath(), file.exists());
+ InputStream input = new FileInputStream(file);
+ Reader reader = new Reader(new UnicodeReader(input));
+ assertEquals('t', reader.peek());
+ reader.forward(1);
+ assertEquals('e', reader.peek());
+ reader.forward(1);
+ assertEquals('s', reader.peek());
+ reader.forward(1);
+ assertEquals('t', reader.peek());
+ reader.forward(1);
+ assertEquals('\u0000', reader.peek());
+ assertEquals(Charset.forName("UTF-16BE"), reader.getEncoding());
+ }
+
+}
diff --git a/src/test/java/org/yaml/snakeyaml/reader/ReaderStringTest.java b/src/test/java/org/yaml/snakeyaml/reader/ReaderStringTest.java new file mode 100644 index 00000000..d4a98f8a --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/reader/ReaderStringTest.java @@ -0,0 +1,61 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.reader;
+
+import java.util.regex.Matcher;
+
+import junit.framework.TestCase;
+
+public class ReaderStringTest extends TestCase {
+
+ public void testCheckPrintable() {
+ Reader reader = new Reader("test");
+ reader.checkPrintable("test");
+ Matcher matcher = Reader.NON_PRINTABLE.matcher("test");
+ assertFalse(matcher.find());
+ }
+
+ public void testCheckNonPrintable() {
+ Matcher matcher = Reader.NON_PRINTABLE.matcher("test\u0005 fail");
+ assertTrue(matcher.find());
+ try {
+ new Reader("test\u0005 fail");
+ fail("Non printable Unicode characters must not be accepted.");
+ } catch (ReaderException e) {
+ assertEquals(
+ "unacceptable character #5 special characters are not allowed\nin \"<string>\", position 4",
+ e.toString());
+ }
+ }
+
+ public void testForward() {
+ Reader reader = new Reader("test");
+ while (reader.peek() != '\u0000') {
+ reader.forward(1);
+ }
+ reader = new Reader("test");
+ assertEquals('t', reader.peek());
+ reader.forward(1);
+ assertEquals('e', reader.peek());
+ reader.forward(1);
+ assertEquals('s', reader.peek());
+ reader.forward(1);
+ assertEquals('t', reader.peek());
+ reader.forward(1);
+ assertEquals('\u0000', reader.peek());
+ }
+
+ public void testPeekInt() {
+ Reader reader = new Reader("test");
+ assertEquals('t', reader.peek(0));
+ assertEquals('e', reader.peek(1));
+ assertEquals('s', reader.peek(2));
+ assertEquals('t', reader.peek(3));
+ reader.forward(1);
+ assertEquals('e', reader.peek(0));
+ assertEquals('s', reader.peek(1));
+ assertEquals('t', reader.peek(2));
+ }
+
+}
diff --git a/src/test/java/org/yaml/snakeyaml/representer/RepresentTest.java b/src/test/java/org/yaml/snakeyaml/representer/RepresentTest.java new file mode 100644 index 00000000..89f1c386 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/representer/RepresentTest.java @@ -0,0 +1,83 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.representer;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Dumper;
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Loader;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.Construct;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.ScalarNode;
+
+public class RepresentTest extends TestCase {
+
+ public void testCustomRepresenter() {
+ Dumper dumper = new Dumper(new MyRepresenter(), new DumperOptions());
+ Loader loader = new Loader(new MyConstructor());
+ Yaml yaml = new Yaml(loader, dumper);
+ CustomBean etalon = new CustomBean("A", 1);
+ String output = yaml.dump(etalon);
+ assertEquals("!!Dice 'Ad1'\n", output);
+ CustomBean bean = (CustomBean) yaml.load(output);
+ assertEquals("A", bean.getPrefix());
+ assertEquals(1, bean.getSuffix());
+ assertEquals(etalon, bean);
+ }
+
+ class CustomBean {
+ private String prefix;
+ private int suffix;
+
+ public CustomBean(String prefix, int suffix) {
+ this.prefix = prefix;
+ this.suffix = suffix;
+ }
+
+ public String getPrefix() {
+ return prefix;
+ }
+
+ public int getSuffix() {
+ return suffix;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ CustomBean bean = (CustomBean) obj;
+ return prefix.equals(bean.getPrefix()) && suffix == bean.getSuffix();
+ }
+ }
+
+ class MyRepresenter extends Representer {
+ public MyRepresenter() {
+ this.representers.put(CustomBean.class, new RepresentDice());
+ }
+
+ private class RepresentDice implements Represent {
+ public Node representData(Object data) {
+ CustomBean coin = (CustomBean) data;
+ String value = coin.getPrefix() + "d" + coin.getSuffix();
+ return representScalar("!!Dice", value);
+ }
+ }
+ }
+
+ class MyConstructor extends Constructor {
+
+ public MyConstructor() {
+ this.yamlConstructors.put("tag:yaml.org,2002:Dice", new ConstuctDice());
+ }
+
+ private class ConstuctDice implements Construct {
+ public Object construct(Node node) {
+ String val = (String) constructScalar((ScalarNode) node);
+ return new CustomBean(val.substring(0, 1), Integer.parseInt(val.substring(2)));
+ }
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/representer/RepresenterTest.java b/src/test/java/org/yaml/snakeyaml/representer/RepresenterTest.java new file mode 100644 index 00000000..af050360 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/representer/RepresenterTest.java @@ -0,0 +1,131 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.representer;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+
+public class RepresenterTest extends TestCase {
+
+ public void testRepresenter() {
+ MyBean bean = new MyBean();
+ bean.setName("Gnome");
+ bean.setValid(true);
+ bean.setPrimitive(true);
+ Yaml yaml = new Yaml();
+ assertEquals(
+ "!!org.yaml.snakeyaml.representer.RepresenterTest$MyBean {name: Gnome, primitive: true}\n",
+ yaml.dump(bean));
+ }
+
+ public static class MyBean {
+ private String name;
+ private Boolean valid;
+ private boolean primitive;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Boolean isValid() {
+ return valid;
+ }
+
+ public void setValid(Boolean valid) {
+ this.valid = valid;
+ }
+
+ public boolean isPrimitive() {
+ return primitive;
+ }
+
+ public void setPrimitive(boolean primitive) {
+ this.primitive = primitive;
+ }
+ }
+
+ public void testRepresenterNoConstructorAvailable() {
+ MyBean2 bean = new MyBean2("Gnome", true);
+ Yaml yaml = new Yaml();
+ assertEquals("!!org.yaml.snakeyaml.representer.RepresenterTest$MyBean2 {valid: true}\n",
+ yaml.dump(bean));
+ }
+
+ public static class MyBean2 {
+ private String name;
+ private Boolean valid;
+
+ public MyBean2(String name, Boolean valid) {
+ this();
+ this.name = name;
+ this.valid = valid;
+ }
+
+ private MyBean2() {
+ super();
+ }
+
+ private String getName() {
+ return name;
+ }
+
+ public Boolean getValid() {
+ return valid;
+ }
+
+ @Override
+ public String toString() {
+ return getName() + " " + getValid();
+ }
+ }
+
+ public void testRepresenterGetterWithException() {
+ MyBean3 bean = new MyBean3("Gnome", true);
+ Yaml yaml = new Yaml();
+ try {
+ yaml.dump(bean);
+ fail("Exception must be reported");
+ } catch (Exception e) {
+ assertTrue(true);
+ }
+ }
+
+ public static class MyBean3 {
+ private String name;
+ private Boolean valid;
+
+ public MyBean3(String name, Boolean valid) {
+ this.name = name;
+ this.valid = valid;
+ }
+
+ public String getName() {
+ throw new UnsupportedOperationException("Test.");
+ }
+
+ public Boolean isValid() {
+ return valid;
+ }
+
+ @Override
+ public String toString() {
+ return name + " " + isValid();
+ }
+ }
+
+ public void testRepresenterAddNull() {
+ Representer representer = new Representer();
+ try {
+ representer.addTypeDescription(null);
+ fail("Representer must be provided.");
+ } catch (Exception e) {
+ assertTrue(true);
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/representer/SafeRepresenterTest.java b/src/test/java/org/yaml/snakeyaml/representer/SafeRepresenterTest.java new file mode 100644 index 00000000..262161a7 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/representer/SafeRepresenterTest.java @@ -0,0 +1,105 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.representer;
+
+import java.math.BigInteger;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Yaml;
+
+public class SafeRepresenterTest extends TestCase {
+
+ public void testBinaryPattern() {
+ Pattern pattern = SafeRepresenter.BINARY_PATTERN;
+ assertFalse(pattern.matcher("\tAndrey\r\n").find());
+ assertTrue(pattern.matcher("\u0005Andrey").find());
+ }
+
+ public void testFloat() {
+ assertEquals("1.0E12", new Double("1e12").toString());
+ }
+
+ public void testNumber() {
+ List<Number> list = new LinkedList<Number>();
+ list.add(new Byte((byte) 3));
+ list.add(new Short((short) 4));
+ list.add(new Integer(5));
+ list.add(new BigInteger("6"));
+ list.add(new Long(7L));
+ list.add(Double.POSITIVE_INFINITY);
+ list.add(Double.NEGATIVE_INFINITY);
+ list.add(Double.NaN);
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(list);
+ assertEquals("[3, 4, 5, 6, 7, .inf, -.inf, .NaN]\n", output);
+ }
+
+ public void testDate() {
+ List<Date> list = new LinkedList<Date>();
+ list.add(new Date(1229684761159L));
+ list.add(new Date(1229684761059L));
+ list.add(new Date(1229684761009L));
+ list.add(new Date(1229684761150L));
+ list.add(new Date(1229684761100L));
+ list.add(new Date(1229684761000L));
+ list.add(new Date(1229684760000L));
+ DumperOptions options = new DumperOptions();
+ options.setDefaultFlowStyle(DumperOptions.DefaultFlowStyle.BLOCK);
+ Yaml yaml = new Yaml(options);
+ String output = yaml.dump(list);
+ assertEquals(
+ "- 2008-12-19T11:06:01.159Z\n- 2008-12-19T11:06:01.059Z\n- 2008-12-19T11:06:01.009Z\n- 2008-12-19T11:06:01.150Z\n- 2008-12-19T11:06:01.100Z\n- 2008-12-19T11:06:01Z\n- 2008-12-19T11:06:00Z\n",
+ output);
+ }
+
+ public void testEmptyArray() {
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(new String[0]);
+ assertEquals("[]\n", output);
+ }
+
+ public void testStyle() {
+ List<Integer> list = new LinkedList<Integer>();
+ list.add(new Integer(1));
+ list.add(new Integer(1));
+ Map<String, Object> map = new HashMap<String, Object>();
+ map.put("list", list);
+ map.put("name", "Ubuntu");
+ map.put("age", 5);
+ DumperOptions options = new DumperOptions();
+ options.setDefaultStyle(DumperOptions.DefaultScalarStyle.DOUBLE_QUOTED);
+ options.setDefaultFlowStyle(DumperOptions.DefaultFlowStyle.BLOCK);
+ Yaml yaml = new Yaml(options);
+ String output = yaml.dump(map);
+ assertTrue(output.contains("\"age\": !!int \"5\""));
+ assertTrue(output.contains("\"name\": \"Ubuntu\""));
+ assertTrue(output.contains("- !!int \"1\""));
+ }
+
+ public void testStyle2() {
+ List<Integer> list = new LinkedList<Integer>();
+ list.add(new Integer(1));
+ list.add(new Integer(1));
+ Map<String, Object> map = new LinkedHashMap<String, Object>();
+ map.put("age", 5);
+ map.put("name", "Ubuntu");
+ map.put("list", list);
+ DumperOptions options = new DumperOptions();
+ options.setDefaultStyle(DumperOptions.DefaultScalarStyle.SINGLE_QUOTED);
+ options.setDefaultFlowStyle(DumperOptions.DefaultFlowStyle.FLOW);
+ Yaml yaml = new Yaml(options);
+ String output = yaml.dump(map);
+ assertEquals("{'age': !!int '5', 'name': 'Ubuntu', 'list': [!!int '1', !!int '1']}\n",
+ output);
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/resolver/RagelMachine.java b/src/test/java/org/yaml/snakeyaml/resolver/RagelMachine.java new file mode 100644 index 00000000..324d869b --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/resolver/RagelMachine.java @@ -0,0 +1,317 @@ +// line 1 "RagelMachine.rl" +/* + * See LICENSE file in distribution for copyright and licensing information. + */ +package org.yaml.snakeyaml.resolver; + +//Source for Ragel 6.3 + +/** + * Generated by Ragel 6.3 (http://www.complang.org/ragel/) + * + * @see http://www.complang.org/ragel/ + */ +public class RagelMachine { + + // line 15 "RagelMachine.java" + private static byte[] init__snakeyaml_actions_0() { + return new byte[] { 0, 1, 0, 1, 1, 1, 2, 1, 3, 1, 4, 1, 5, 1, 6 }; + } + + private static final byte _snakeyaml_actions[] = init__snakeyaml_actions_0(); + + private static short[] init__snakeyaml_key_offsets_0() { + return new short[] { 0, 0, 20, 24, 28, 30, 32, 34, 35, 36, 37, 42, 46, 50, 52, 56, 59, 66, + 70, 74, 80, 82, 83, 84, 85, 87, 90, 92, 98, 102, 105, 106, 108, 110, 111, 113, 115, + 120, 122, 124, 126, 130, 132, 133, 135, 141, 147, 152, 157, 158, 160, 161, 162, + 163, 164, 165, 166, 170, 171, 172, 173, 174, 178, 179, 180, 182, 183, 184, 186, + 187, 188, 189, 191, 193, 194, 195, 195, 200, 202, 202, 211, 218, 224, 227, 234, + 239, 243, 245, 250, 253, 254, 263, 270, 277, 285, 291, 294, 295, 295, 302, 306, + 311, 316, 321, 327, 327, 327 }; + } + + private static final short _snakeyaml_key_offsets[] = init__snakeyaml_key_offsets_0(); + + private static char[] init__snakeyaml_trans_keys_0() { + return new char[] { 32, 43, 45, 46, 48, 60, 61, 70, 78, 79, 84, 89, 102, 110, 111, 116, + 121, 126, 49, 57, 46, 48, 49, 57, 73, 105, 48, 57, 43, 45, 48, 57, 78, 110, 70, + 102, 110, 46, 58, 95, 48, 57, 48, 53, 54, 57, 46, 58, 48, 57, 46, 58, 46, 95, 48, + 57, 95, 48, 49, 95, 48, 57, 65, 70, 97, 102, 48, 53, 54, 57, 48, 53, 54, 57, 73, + 78, 105, 110, 48, 57, 65, 97, 78, 97, 110, 48, 57, 45, 48, 57, 48, 57, 9, 32, 84, + 116, 48, 57, 9, 32, 48, 57, 58, 48, 57, 58, 48, 57, 48, 57, 58, 48, 57, 48, 57, 9, + 32, 43, 45, 90, 48, 57, 48, 57, 48, 57, 9, 32, 84, 116, 48, 57, 45, 48, 57, 9, 32, + 84, 116, 48, 57, 45, 46, 58, 95, 48, 57, 46, 58, 95, 48, 57, 46, 58, 95, 48, 57, + 60, 65, 97, 76, 83, 69, 108, 115, 101, 79, 85, 111, 117, 76, 76, 108, 108, 70, 78, + 102, 110, 70, 102, 82, 114, 85, 117, 69, 101, 83, 115, 97, 111, 117, 102, 110, 114, + 101, 69, 95, 101, 48, 57, 48, 57, 46, 58, 95, 98, 120, 48, 55, 56, 57, 46, 58, 95, + 48, 55, 56, 57, 46, 95, 48, 55, 56, 57, 95, 48, 49, 95, 48, 57, 65, 70, 97, 102, + 46, 58, 95, 48, 57, 46, 58, 48, 57, 46, 58, 46, 58, 95, 48, 57, 58, 48, 57, 58, 46, + 58, 95, 98, 120, 48, 55, 56, 57, 46, 58, 95, 48, 55, 56, 57, 46, 58, 95, 48, 55, + 56, 57, 45, 46, 58, 95, 48, 55, 56, 57, 9, 32, 43, 45, 46, 90, 58, 48, 57, 58, 9, + 32, 43, 45, 90, 48, 57, 9, 32, 84, 116, 46, 58, 95, 48, 57, 46, 58, 95, 48, 57, 46, + 58, 95, 48, 57, 45, 46, 58, 95, 48, 57, 0 }; + } + + private static final char _snakeyaml_trans_keys[] = init__snakeyaml_trans_keys_0(); + + private static byte[] init__snakeyaml_single_lengths_0() { + return new byte[] { 0, 18, 2, 2, 2, 0, 2, 1, 1, 1, 3, 0, 2, 2, 2, 1, 1, 0, 0, 4, 2, 1, 1, + 1, 0, 1, 0, 4, 2, 1, 1, 0, 0, 1, 0, 0, 5, 0, 0, 0, 4, 0, 1, 0, 4, 4, 3, 3, 1, 2, 1, + 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 4, 1, 1, 2, 1, 1, 2, 1, 1, 1, 2, 2, 1, 1, 0, 3, 0, 0, + 5, 3, 2, 1, 1, 3, 2, 2, 3, 1, 1, 5, 3, 3, 4, 6, 1, 1, 0, 5, 4, 3, 3, 3, 4, 0, 0, 0 }; + } + + private static final byte _snakeyaml_single_lengths[] = init__snakeyaml_single_lengths_0(); + + private static byte[] init__snakeyaml_range_lengths_0() { + return new byte[] { 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 2, 1, 0, 1, 1, 3, 2, 2, 1, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 2, + 2, 2, 1, 3, 1, 1, 0, 1, 1, 0, 2, 2, 2, 2, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0 }; + } + + private static final byte _snakeyaml_range_lengths[] = init__snakeyaml_range_lengths_0(); + + private static short[] init__snakeyaml_index_offsets_0() { + return new short[] { 0, 0, 20, 24, 28, 31, 33, 36, 38, 40, 42, 47, 50, 54, 57, 61, 64, 69, + 72, 75, 81, 84, 86, 88, 90, 92, 95, 97, 103, 107, 110, 112, 114, 116, 118, 120, + 122, 128, 130, 132, 134, 139, 141, 143, 145, 151, 157, 162, 167, 169, 172, 174, + 176, 178, 180, 182, 184, 189, 191, 193, 195, 197, 202, 204, 206, 209, 211, 213, + 216, 218, 220, 222, 225, 228, 230, 232, 233, 238, 240, 241, 249, 255, 260, 263, + 268, 273, 277, 280, 285, 288, 290, 298, 304, 310, 317, 324, 327, 329, 330, 337, + 342, 347, 352, 357, 363, 364, 365 }; + } + + private static final short _snakeyaml_index_offsets[] = init__snakeyaml_index_offsets_0(); + + private static byte[] init__snakeyaml_indicies_0() { + return new byte[] { 0, 2, 2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 0, 5, 1, 18, + 19, 20, 1, 22, 23, 21, 1, 24, 24, 1, 25, 1, 26, 27, 1, 28, 1, 28, 1, 27, 1, 21, 30, + 31, 29, 1, 32, 33, 1, 25, 30, 33, 1, 25, 30, 1, 21, 31, 31, 1, 34, 34, 1, 35, 35, + 35, 35, 1, 36, 37, 1, 38, 39, 1, 22, 40, 23, 41, 21, 1, 42, 42, 1, 28, 1, 43, 1, + 28, 1, 44, 1, 45, 46, 1, 47, 1, 48, 48, 50, 50, 49, 1, 48, 48, 51, 1, 53, 52, 1, + 53, 1, 54, 1, 55, 1, 56, 1, 57, 1, 58, 1, 59, 59, 60, 60, 61, 1, 62, 1, 63, 1, 61, + 1, 48, 48, 50, 50, 1, 51, 1, 64, 1, 65, 1, 48, 48, 50, 50, 66, 1, 67, 21, 30, 31, + 29, 1, 21, 30, 31, 68, 1, 21, 30, 31, 69, 1, 70, 1, 71, 72, 1, 73, 1, 74, 1, 75, 1, + 76, 1, 77, 1, 75, 1, 75, 78, 75, 79, 1, 80, 1, 0, 1, 81, 1, 0, 1, 82, 75, 83, 75, + 1, 75, 1, 75, 1, 84, 85, 1, 74, 1, 77, 1, 86, 87, 1, 75, 1, 75, 1, 72, 1, 75, 79, + 1, 83, 75, 1, 85, 1, 87, 1, 1, 88, 21, 88, 21, 1, 25, 1, 1, 21, 30, 90, 91, 92, 89, + 29, 1, 21, 30, 90, 89, 29, 1, 21, 90, 90, 31, 1, 34, 34, 1, 35, 35, 35, 35, 1, 21, + 93, 94, 20, 1, 25, 93, 37, 1, 25, 93, 1, 21, 95, 94, 94, 1, 95, 39, 1, 95, 1, 21, + 30, 90, 91, 92, 96, 97, 1, 21, 30, 90, 98, 69, 1, 21, 30, 90, 99, 68, 1, 67, 21, + 30, 90, 89, 29, 1, 59, 59, 60, 60, 100, 61, 1, 102, 101, 1, 102, 1, 1, 59, 59, 60, + 60, 61, 100, 1, 48, 48, 50, 50, 1, 21, 93, 94, 103, 1, 21, 93, 94, 104, 1, 21, 93, + 94, 105, 1, 67, 21, 93, 94, 20, 1, 1, 1, 1, 0 }; + } + + private static final byte _snakeyaml_indicies[] = init__snakeyaml_indicies_0(); + + private static byte[] init__snakeyaml_trans_targs_0() { + return new byte[] { 75, 0, 2, 19, 90, 100, 48, 105, 49, 56, 61, 64, 67, 70, 71, 72, 73, 74, + 3, 79, 84, 76, 6, 9, 5, 77, 7, 8, 78, 10, 11, 14, 12, 13, 82, 83, 85, 86, 88, 89, + 20, 22, 21, 23, 25, 26, 42, 27, 28, 40, 41, 29, 30, 31, 32, 33, 34, 35, 94, 36, 37, + 97, 95, 39, 43, 44, 99, 24, 45, 46, 104, 50, 53, 51, 52, 106, 54, 55, 57, 59, 58, + 60, 62, 63, 65, 66, 68, 69, 4, 80, 81, 15, 16, 17, 87, 18, 91, 47, 92, 93, 98, 96, + 38, 101, 102, 103 }; + } + + private static final byte _snakeyaml_trans_targs[] = init__snakeyaml_trans_targs_0(); + + // private static byte[] init__snakeyaml_trans_actions_0() { + // return new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // 0, 0, 0, 0, 0, 0, + // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // 0, 0, 0, 0, + // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // 0, 0, 0, 0, + // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // 0, 0 }; + // } + + // private static final byte _snakeyaml_trans_actions[] = + // init__snakeyaml_trans_actions_0(); + + private static byte[] init__snakeyaml_eof_actions_0() { + return new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 11, 11, 11, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 13, 13, 13, 13, 13, 13, 9, 9, 9, 9, 3, + 7, 1 }; + } + + private static final byte _snakeyaml_eof_actions[] = init__snakeyaml_eof_actions_0(); + + static final int snakeyaml_start = 1; + static final int snakeyaml_error = 0; + + static final int snakeyaml_en_main = 1; + + // line 53 "RagelMachine.rl" + + public String scan(String scalar) { + if (scalar == null) { + throw new NullPointerException("Scalar must be provided."); + } + String tag = null; + int cs = 0; + int p = 0; + int pe = scalar.length(); + int eof = pe; + char[] data; + if (pe == 0) { + // NULL value
+ data = new char[] { '~' }; + pe = 1; + eof = 1; + } else { + data = scalar.toCharArray(); + } + + // line 257 "RagelMachine.java" + { + cs = snakeyaml_start; + } + + // line 262 "RagelMachine.java" + { + int _klen; + int _trans = 0; + int _keys; + int _goto_targ = 0; + + _goto: while (true) { + switch (_goto_targ) { + case 0: + if (p == pe) { + _goto_targ = 4; + continue _goto; + } + if (cs == 0) { + _goto_targ = 5; + continue _goto; + } + case 1: + _match: do { + _keys = _snakeyaml_key_offsets[cs]; + _trans = _snakeyaml_index_offsets[cs]; + _klen = _snakeyaml_single_lengths[cs]; + if (_klen > 0) { + int _lower = _keys; + int _mid; + int _upper = _keys + _klen - 1; + while (true) { + if (_upper < _lower) + break; + + _mid = _lower + ((_upper - _lower) >> 1); + if (data[p] < _snakeyaml_trans_keys[_mid]) + _upper = _mid - 1; + else if (data[p] > _snakeyaml_trans_keys[_mid]) + _lower = _mid + 1; + else { + _trans += (_mid - _keys); + break _match; + } + } + _keys += _klen; + _trans += _klen; + } + + _klen = _snakeyaml_range_lengths[cs]; + if (_klen > 0) { + int _lower = _keys; + int _mid; + int _upper = _keys + (_klen << 1) - 2; + while (true) { + if (_upper < _lower) + break; + + _mid = _lower + (((_upper - _lower) >> 1) & ~1); + if (data[p] < _snakeyaml_trans_keys[_mid]) + _upper = _mid - 2; + else if (data[p] > _snakeyaml_trans_keys[_mid + 1]) + _lower = _mid + 2; + else { + _trans += ((_mid - _keys) >> 1); + break _match; + } + } + _trans += _klen; + } + } while (false); + + _trans = _snakeyaml_indicies[_trans]; + cs = _snakeyaml_trans_targs[_trans]; + + case 2: + if (cs == 0) { + _goto_targ = 5; + continue _goto; + } + if (++p != pe) { + _goto_targ = 1; + continue _goto; + } + case 4: + if (p == eof) { + int __acts = _snakeyaml_eof_actions[cs]; + int __nacts = (int) _snakeyaml_actions[__acts++]; + while (__nacts-- > 0) { + switch (_snakeyaml_actions[__acts++]) { + case 0: + // line 14 "RagelMachine.rl" + { + tag = "tag:yaml.org,2002:bool"; + } + break; + case 1: + // line 15 "RagelMachine.rl" + { + tag = "tag:yaml.org,2002:merge"; + } + break; + case 2: + // line 16 "RagelMachine.rl" + { + tag = "tag:yaml.org,2002:null"; + } + break; + case 3: + // line 17 "RagelMachine.rl" + { + tag = "tag:yaml.org,2002:value"; + } + break; + case 4: + // line 18 "RagelMachine.rl" + { + tag = "tag:yaml.org,2002:int"; + } + break; + case 5: + // line 19 "RagelMachine.rl" + { + tag = "tag:yaml.org,2002:float"; + } + break; + case 6: + // line 20 "RagelMachine.rl" + { + tag = "tag:yaml.org,2002:timestamp"; + } + break; + // line 377 "RagelMachine.java" + } + } + } + + case 5: + } + break; + } + } + // line 77 "RagelMachine.rl" + + return tag; + } +}
\ No newline at end of file diff --git a/src/test/java/org/yaml/snakeyaml/resolver/RagelMachineTest.java b/src/test/java/org/yaml/snakeyaml/resolver/RagelMachineTest.java new file mode 100644 index 00000000..1ad62ccc --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/resolver/RagelMachineTest.java @@ -0,0 +1,104 @@ +package org.yaml.snakeyaml.resolver;
+
+import junit.framework.TestCase;
+
+public class RagelMachineTest extends TestCase {
+ private RagelMachine machine = new RagelMachine();
+
+ public void testScan() {
+ assertNull(machine.scan("abc"));
+ }
+
+ public void testNullPointerException() {
+ try {
+ machine.scan(null);
+ fail("null must not be accepted.");
+ } catch (NullPointerException e) {
+ assertEquals("Scalar must be provided.", e.getMessage());
+ }
+ }
+
+ public void testScanBoolean() {
+ assertEquals("tag:yaml.org,2002:bool", machine.scan("true"));
+ assertEquals("tag:yaml.org,2002:bool", machine.scan("True"));
+ assertEquals("tag:yaml.org,2002:bool", machine.scan("TRUE"));
+ assertEquals("tag:yaml.org,2002:bool", machine.scan("false"));
+ assertEquals("tag:yaml.org,2002:bool", machine.scan("False"));
+ assertEquals("tag:yaml.org,2002:bool", machine.scan("FALSE"));
+ assertEquals("tag:yaml.org,2002:bool", machine.scan("on"));
+ assertEquals("tag:yaml.org,2002:bool", machine.scan("ON"));
+ assertEquals("tag:yaml.org,2002:bool", machine.scan("On"));
+ assertEquals("tag:yaml.org,2002:bool", machine.scan("off"));
+ assertEquals("tag:yaml.org,2002:bool", machine.scan("Off"));
+ assertEquals("tag:yaml.org,2002:bool", machine.scan("OFF"));
+ assertEquals("tag:yaml.org,2002:bool", machine.scan("on"));
+ assertEquals("tag:yaml.org,2002:bool", machine.scan("ON"));
+ assertEquals("tag:yaml.org,2002:bool", machine.scan("On"));
+ assertEquals("tag:yaml.org,2002:bool", machine.scan("off"));
+ assertEquals("tag:yaml.org,2002:bool", machine.scan("Off"));
+ assertEquals("tag:yaml.org,2002:bool", machine.scan("OFF"));
+ }
+
+ public void testScanNull() {
+ assertEquals("tag:yaml.org,2002:null", machine.scan("null"));
+ assertEquals("tag:yaml.org,2002:null", machine.scan("Null"));
+ assertEquals("tag:yaml.org,2002:null", machine.scan("NULL"));
+ assertEquals("tag:yaml.org,2002:null", machine.scan("~"));
+ assertEquals("tag:yaml.org,2002:null", machine.scan(" "));
+ assertEquals("tag:yaml.org,2002:null", machine.scan(""));
+ }
+
+ public void testScanMerge() {
+ assertEquals("tag:yaml.org,2002:merge", machine.scan("<<"));
+ }
+
+ public void testScanValue() {
+ assertEquals("tag:yaml.org,2002:value", machine.scan("="));
+ }
+
+ public void testScanInt() {
+ assertEquals("tag:yaml.org,2002:int", machine.scan("0"));
+ assertEquals("tag:yaml.org,2002:int", machine.scan("1"));
+ assertEquals("tag:yaml.org,2002:int", machine.scan("-0"));
+ assertEquals("tag:yaml.org,2002:int", machine.scan("-9"));
+ assertEquals("tag:yaml.org,2002:int", machine.scan("0b0011"));
+ assertEquals("tag:yaml.org,2002:int", machine.scan("0x12ef"));
+ assertEquals("tag:yaml.org,2002:int", machine.scan("0123"));
+ assertEquals("tag:yaml.org,2002:int", machine.scan("1_000"));
+ assertEquals("tag:yaml.org,2002:int", machine.scan("1_000_000"));
+ assertEquals("tag:yaml.org,2002:int", machine.scan("+0"));
+ assertEquals("tag:yaml.org,2002:int", machine.scan("+10"));
+ assertEquals("tag:yaml.org,2002:int", machine.scan("1__000"));
+ assertEquals("tag:yaml.org,2002:int", machine.scan("24:12:34"));
+ assertEquals("tag:yaml.org,2002:int", machine.scan("240:12:34"));
+ }
+
+ public void testScanFloat() {
+ assertEquals("tag:yaml.org,2002:float", machine.scan("1.0"));
+ assertEquals("tag:yaml.org,2002:float", machine.scan("-0.0"));
+ assertEquals("tag:yaml.org,2002:float", machine.scan("+2.2310"));
+ assertEquals("tag:yaml.org,2002:float", machine.scan("1.0e+12"));
+ assertEquals("tag:yaml.org,2002:float", machine.scan("1.345e-3"));
+ assertEquals("tag:yaml.org,2002:float", machine.scan("190:20:30.15"));
+ assertEquals("tag:yaml.org,2002:float", machine.scan("-.inf"));
+ assertEquals("tag:yaml.org,2002:float", machine.scan("+.INF"));
+ assertEquals("tag:yaml.org,2002:float", machine.scan(".Inf"));
+ assertEquals("tag:yaml.org,2002:float", machine.scan(".nan"));
+ assertEquals("tag:yaml.org,2002:float", machine.scan(".NaN"));
+ assertEquals("tag:yaml.org,2002:float", machine.scan(".NAN"));
+ assertEquals("tag:yaml.org,2002:float", machine.scan("1_000.5"));
+ assertEquals("tag:yaml.org,2002:float", machine.scan("1.023_456"));
+ assertEquals("tag:yaml.org,2002:float", machine.scan("-1_123.45"));
+ assertEquals("tag:yaml.org,2002:float", machine.scan(".5"));
+ assertEquals("tag:yaml.org,2002:float", machine.scan("1.E+1"));
+ assertNull(machine.scan("0x1,1"), machine.scan("0x1,1"));
+ }
+
+ public void testScanTimestamp() {
+ assertEquals("tag:yaml.org,2002:timestamp", machine.scan("2009-02-28"));
+ assertEquals("tag:yaml.org,2002:timestamp", machine.scan("2001-12-15T02:59:43.1Z"));
+ assertEquals("tag:yaml.org,2002:timestamp", machine.scan("2001-12-14t21:59:43.10-05:00"));
+ assertEquals("tag:yaml.org,2002:timestamp", machine.scan("2001-12-14 21:59:43.10 -5"));
+ assertEquals("tag:yaml.org,2002:timestamp", machine.scan("2001-12-15 2:59:43.10"));
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/resolver/ResolverTest.java b/src/test/java/org/yaml/snakeyaml/resolver/ResolverTest.java new file mode 100644 index 00000000..94bd291f --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/resolver/ResolverTest.java @@ -0,0 +1,141 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.resolver;
+
+import java.awt.Point;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Dumper;
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Loader;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.Construct;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.ScalarNode;
+import org.yaml.snakeyaml.representer.Represent;
+import org.yaml.snakeyaml.representer.Representer;
+
+public class ResolverTest extends TestCase {
+
+ @SuppressWarnings("unchecked")
+ public void testAddImplicitResolver() {
+ Dumper dumper = new Dumper(new MyRepresenter(), new DumperOptions());
+ Loader loader = new Loader(new MyConstructor());
+ Yaml yaml = new Yaml(loader, dumper);
+ Pattern regexp = Pattern.compile("\\d\\d-\\d\\d-\\d\\d\\d");
+ yaml.addImplicitResolver("tag:yaml.org,2002:Phone", regexp, "0123456789");
+ Phone phone1 = new Phone("12-34-567");
+ Phone phone2 = new Phone("11-22-333");
+ Phone phone3 = new Phone("44-55-777");
+ List<Phone> etalonList = new LinkedList<Phone>();
+ etalonList.add(phone1);
+ etalonList.add(phone2);
+ etalonList.add(phone3);
+ String output = yaml.dump(etalonList);
+ assertEquals("[12-34-567, 11-22-333, 44-55-777]\n", output);
+ List<Phone> parsedList = (List<Phone>) yaml.load(output);
+ assertEquals(3, parsedList.size());
+ assertEquals(phone1, parsedList.get(0));
+ assertEquals(phone2, parsedList.get(1));
+ assertEquals(phone3, parsedList.get(2));
+ assertEquals(etalonList, parsedList);
+ }
+
+ public void testAddImplicitResolver2() {
+ Dumper dumper = new Dumper(new PointRepresenter(), new DumperOptions());
+ Yaml yaml = new Yaml(dumper);
+ Pattern regexp = Pattern.compile("\\d\\d-\\d\\d-\\d\\d\\d");
+ yaml.addImplicitResolver("tag:yaml.org,2002:Phone", regexp, "\0");
+ Pattern regexp2 = Pattern.compile("x\\d_y\\d");
+ // try any scalar, and not only those which start with 'x'
+ yaml.addImplicitResolver("tag:yaml.org,2002:Point", regexp2, null);
+ Map<String, Object> map = new LinkedHashMap<String, Object>();
+ map.put("a", new Phone("12-34-567"));
+ map.put("b", new Point(1, 5));
+ String output = yaml.dump(map);
+ assertEquals("{a: 12-34-567, b: x1_y5}\n", output);
+ }
+
+ class Phone {
+ private String number;
+
+ public Phone(String n) {
+ this.number = n;
+ }
+
+ public String getNumber() {
+ return number;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof Phone)) {
+ return false;
+ }
+ return toString().equals(obj.toString());
+ }
+
+ @Override
+ public String toString() {
+ return "Phone: " + number;
+ }
+ }
+
+ class MyRepresenter extends Representer {
+ public MyRepresenter() {
+ this.representers.put(Phone.class, new RepresentPhone());
+ }
+
+ private class RepresentPhone implements Represent {
+ public Node representData(Object data) {
+ Phone phone = (Phone) data;
+ String value = phone.getNumber();
+ return representScalar("tag:yaml.org,2002:Phone", value);
+ }
+ }
+ }
+
+ class MyConstructor extends Constructor {
+ public MyConstructor() {
+ this.yamlConstructors.put("tag:yaml.org,2002:Phone", new ConstuctPhone());
+ }
+
+ private class ConstuctPhone implements Construct {
+ public Object construct(Node node) {
+ String val = (String) constructScalar((ScalarNode) node);
+ return new Phone(val);
+ }
+ }
+ }
+
+ class PointRepresenter extends Representer {
+ public PointRepresenter() {
+ this.representers.put(Point.class, new RepresentPoint());
+ this.representers.put(Phone.class, new RepresentPhone());
+ }
+
+ private class RepresentPoint implements Represent {
+ public Node representData(Object data) {
+ Point phone = (Point) data;
+ String value = "x" + (int) phone.getX() + "_y" + (int) phone.getY();
+ return representScalar("tag:yaml.org,2002:Point", value);
+ }
+ }
+
+ private class RepresentPhone implements Represent {
+ public Node representData(Object data) {
+ Phone phone = (Phone) data;
+ String value = phone.getNumber();
+ return representScalar("tag:yaml.org,2002:Phone", value);
+ }
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/resolver/ResolverTupleTest.java b/src/test/java/org/yaml/snakeyaml/resolver/ResolverTupleTest.java new file mode 100644 index 00000000..763291af --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/resolver/ResolverTupleTest.java @@ -0,0 +1,16 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.resolver;
+
+import java.util.regex.Pattern;
+
+import junit.framework.TestCase;
+
+public class ResolverTupleTest extends TestCase {
+
+ public void testToString() {
+ ResolverTuple tuple = new ResolverTuple("dice", Pattern.compile("\\d+"));
+ assertEquals("Tuple tag=dice regexp=\\d+", tuple.toString());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/scanner/ScannerImplTest.java b/src/test/java/org/yaml/snakeyaml/scanner/ScannerImplTest.java new file mode 100644 index 00000000..4486522d --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/scanner/ScannerImplTest.java @@ -0,0 +1,47 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.scanner;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.error.Mark;
+import org.yaml.snakeyaml.reader.Reader;
+import org.yaml.snakeyaml.tokens.BlockEndToken;
+import org.yaml.snakeyaml.tokens.BlockMappingStartToken;
+import org.yaml.snakeyaml.tokens.KeyToken;
+import org.yaml.snakeyaml.tokens.ScalarToken;
+import org.yaml.snakeyaml.tokens.StreamEndToken;
+import org.yaml.snakeyaml.tokens.StreamStartToken;
+import org.yaml.snakeyaml.tokens.Token;
+import org.yaml.snakeyaml.tokens.ValueToken;
+
+public class ScannerImplTest extends TestCase {
+
+ @SuppressWarnings("unchecked")
+ public void testGetToken() {
+ String data = "string: abcd";
+ Reader reader = new Reader(data);
+ Scanner scanner = new ScannerImpl(reader);
+
+ Mark dummy = new Mark("dummy", 0, 0, 0, "", 0);
+ LinkedList<Token> etalonTokens = new LinkedList<Token>();
+ etalonTokens.add(new StreamStartToken(dummy, dummy));
+ etalonTokens.add(new BlockMappingStartToken(dummy, dummy));
+ etalonTokens.add(new KeyToken(dummy, dummy));
+ etalonTokens.add(new ScalarToken("string", true, dummy, dummy, (char) 0));
+ etalonTokens.add(new ValueToken(dummy, dummy));
+ etalonTokens.add(new ScalarToken("abcd", true, dummy, dummy, (char) 0));
+ etalonTokens.add(new BlockEndToken(dummy, dummy));
+ etalonTokens.add(new StreamEndToken(dummy, dummy));
+ while (scanner.checkToken(new ArrayList())) {
+ assertEquals(etalonTokens.removeFirst(), scanner.getToken());
+ // System.out.println(scanner.getToken());
+ }
+ assertFalse("Must contain no more tokens: " + scanner.getToken(), scanner
+ .checkToken(new ArrayList()));
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/scanner/SimpleKeyTest.java b/src/test/java/org/yaml/snakeyaml/scanner/SimpleKeyTest.java new file mode 100644 index 00000000..ca4a4075 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/scanner/SimpleKeyTest.java @@ -0,0 +1,14 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.scanner;
+
+import junit.framework.TestCase;
+
+public class SimpleKeyTest extends TestCase {
+
+ public void testToString() {
+ SimpleKey key = new SimpleKey(1, false, 5, 3, 2, null);
+ assertTrue(key.toString().contains("SimpleKey"));
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/serializer/SerializerTest.java b/src/test/java/org/yaml/snakeyaml/serializer/SerializerTest.java new file mode 100644 index 00000000..898ff034 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/serializer/SerializerTest.java @@ -0,0 +1,89 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.serializer;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.text.NumberFormat;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.emitter.Emitter;
+import org.yaml.snakeyaml.nodes.ScalarNode;
+import org.yaml.snakeyaml.resolver.Resolver;
+
+public class SerializerTest extends TestCase {
+ private Serializer serializer;
+
+ @Override
+ protected void setUp() throws Exception {
+ DumperOptions config = new DumperOptions();
+ StringWriter writer = new StringWriter();
+ serializer = new Serializer(new Emitter(writer, config), new Resolver(), config);
+ }
+
+ public void testSerializerIsAlreadyOpened() throws IOException {
+ serializer.open();
+ try {
+ serializer.open();
+ fail();
+ } catch (RuntimeException e) {
+ assertEquals("serializer is already opened", e.getMessage());
+ }
+ }
+
+ public void testSerializerIsClosed1() throws IOException {
+ serializer.open();
+ serializer.close();
+ try {
+ serializer.open();
+ fail();
+ } catch (RuntimeException e) {
+ assertEquals("serializer is closed", e.getMessage());
+ }
+ }
+
+ public void testSerializerIsClosed2() throws IOException {
+ serializer.open();
+ serializer.close();
+ try {
+ serializer.serialize(new ScalarNode("!foo", "bar", null, null, (char) 0));
+ fail();
+ } catch (RuntimeException e) {
+ assertEquals("serializer is closed", e.getMessage());
+ }
+ }
+
+ public void testSerializerIsClosed3() throws IOException {
+ serializer.open();
+ serializer.close();
+ serializer.close();// no problem to close twice
+ }
+
+ public void testSerializerIsNotOpened1() throws IOException {
+ try {
+ serializer.close();
+ fail();
+ } catch (RuntimeException e) {
+ assertEquals("serializer is not opened", e.getMessage());
+ }
+ }
+
+ public void testSerializerIsNotOpened2() throws IOException {
+ try {
+ serializer.serialize(new ScalarNode("!foo", "bar", null, null, (char) 0));
+ fail();
+ } catch (RuntimeException e) {
+ assertEquals("serializer is not opened", e.getMessage());
+ }
+ }
+
+ public void testGenerateAnchor() {
+ NumberFormat format = NumberFormat.getNumberInstance();
+ format.setMinimumIntegerDigits(3);
+ String anchor = format.format(3L);
+ assertEquals("003", anchor);
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/tokens/AliasTokenTest.java b/src/test/java/org/yaml/snakeyaml/tokens/AliasTokenTest.java new file mode 100644 index 00000000..c8aed69e --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/tokens/AliasTokenTest.java @@ -0,0 +1,29 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.error.Mark;
+
+public class AliasTokenTest extends TestCase {
+
+ public void testEquals() {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ AliasToken token = new AliasToken("*id123", mark, mark);
+ assertFalse(token.equals(mark));
+ }
+
+ public void testGetArguments() {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ AliasToken token = new AliasToken("*id123", mark, mark);
+ assertEquals("value=*id123", token.getArguments());
+ }
+
+ public void testGetTokenId() {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ AliasToken token = new AliasToken("&id123", mark, mark);
+ assertEquals("<alias>", token.getTokenId());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/tokens/AnchorTokenTest.java b/src/test/java/org/yaml/snakeyaml/tokens/AnchorTokenTest.java new file mode 100644 index 00000000..2352a459 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/tokens/AnchorTokenTest.java @@ -0,0 +1,23 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.error.Mark;
+
+public class AnchorTokenTest extends TestCase {
+
+ public void testGetArguments() {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ AnchorToken token = new AnchorToken("&id123", mark, mark);
+ assertEquals("value=&id123", token.getArguments());
+ }
+
+ public void testGetTokenId() {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ AnchorToken token = new AnchorToken("&id123", mark, mark);
+ assertEquals("<anchor>", token.getTokenId());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/tokens/BlockEndTokenTest.java b/src/test/java/org/yaml/snakeyaml/tokens/BlockEndTokenTest.java new file mode 100644 index 00000000..38cb49b1 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/tokens/BlockEndTokenTest.java @@ -0,0 +1,23 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.error.Mark;
+
+public class BlockEndTokenTest extends TestCase {
+
+ public void testGetArguments() {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ BlockEndToken token = new BlockEndToken(mark, mark);
+ assertEquals("", token.getArguments());
+ }
+
+ public void testGetTokenId() {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ BlockEndToken token = new BlockEndToken(mark, mark);
+ assertEquals("<block end>", token.getTokenId());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/tokens/BlockEntryTokenTest.java b/src/test/java/org/yaml/snakeyaml/tokens/BlockEntryTokenTest.java new file mode 100644 index 00000000..869c2871 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/tokens/BlockEntryTokenTest.java @@ -0,0 +1,18 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.error.Mark;
+
+public class BlockEntryTokenTest extends TestCase {
+
+ public void testGetTokenId() {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ BlockEntryToken token = new BlockEntryToken(mark, mark);
+ assertEquals("-", token.getTokenId());
+ }
+
+}
diff --git a/src/test/java/org/yaml/snakeyaml/tokens/BlockSequenceStartTokenTest.java b/src/test/java/org/yaml/snakeyaml/tokens/BlockSequenceStartTokenTest.java new file mode 100644 index 00000000..38e4096e --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/tokens/BlockSequenceStartTokenTest.java @@ -0,0 +1,17 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.error.Mark;
+
+public class BlockSequenceStartTokenTest extends TestCase {
+
+ public void testGetTokenId() {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ BlockSequenceStartToken token = new BlockSequenceStartToken(mark, mark);
+ assertEquals("<block sequence start>", token.getTokenId());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/tokens/DirectiveTokenTest.java b/src/test/java/org/yaml/snakeyaml/tokens/DirectiveTokenTest.java new file mode 100644 index 00000000..fd765403 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/tokens/DirectiveTokenTest.java @@ -0,0 +1,56 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.error.Mark;
+
+public class DirectiveTokenTest extends TestCase {
+
+ public void testGetArguments() {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ DirectiveToken token = new DirectiveToken("YAML", null, mark, mark);
+ assertEquals("name=YAML", token.getArguments());
+ }
+
+ public void testInvalidList() {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ List<Integer> list = new LinkedList<Integer>();
+ list.add(new Integer(1));
+ try {
+ new DirectiveToken("YAML", list, mark, mark);
+ fail("List must have 2 values.");
+ } catch (Exception e) {
+ assertEquals("Two strings must be provided instead of 1", e.getMessage());
+ }
+ }
+
+ public void testTag() {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ List<String> list = new LinkedList<String>();
+ list.add("!foo");
+ list.add("!bar");
+ DirectiveToken token = new DirectiveToken("TAG", list, mark, mark);
+ assertEquals("name=TAG, value=[!foo, !bar]", token.getArguments());
+ }
+
+ public void testList() {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ List<Integer> list = new LinkedList<Integer>();
+ list.add(new Integer(1));
+ list.add(new Integer(1));
+ DirectiveToken token = new DirectiveToken("YAML", list, mark, mark);
+ assertEquals("name=YAML, value=[1, 1]", token.getArguments());
+ }
+
+ public void testGetTokenId() {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ DirectiveToken token = new DirectiveToken("YAML", null, mark, mark);
+ assertEquals("<directive>", token.getTokenId());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/tokens/DocumentEndTokenTest.java b/src/test/java/org/yaml/snakeyaml/tokens/DocumentEndTokenTest.java new file mode 100644 index 00000000..ed418356 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/tokens/DocumentEndTokenTest.java @@ -0,0 +1,17 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.error.Mark;
+
+public class DocumentEndTokenTest extends TestCase {
+
+ public void testGetTokenId() {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ DocumentEndToken token = new DocumentEndToken(mark, mark);
+ assertEquals("<document end>", token.getTokenId());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/tokens/DocumentStartTokenTest.java b/src/test/java/org/yaml/snakeyaml/tokens/DocumentStartTokenTest.java new file mode 100644 index 00000000..253857f0 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/tokens/DocumentStartTokenTest.java @@ -0,0 +1,17 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.error.Mark;
+
+public class DocumentStartTokenTest extends TestCase {
+
+ public void testGetTokenId() {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ DocumentStartToken token = new DocumentStartToken(mark, mark);
+ assertEquals("<document start>", token.getTokenId());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/tokens/FlowEntryTokenTest.java b/src/test/java/org/yaml/snakeyaml/tokens/FlowEntryTokenTest.java new file mode 100644 index 00000000..c9d3f0b7 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/tokens/FlowEntryTokenTest.java @@ -0,0 +1,17 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.error.Mark;
+
+public class FlowEntryTokenTest extends TestCase {
+
+ public void testGetTokenId() {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ FlowEntryToken token = new FlowEntryToken(mark, mark);
+ assertEquals(",", token.getTokenId());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/tokens/FlowMappingStartTokenTest.java b/src/test/java/org/yaml/snakeyaml/tokens/FlowMappingStartTokenTest.java new file mode 100644 index 00000000..5c5cf4ef --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/tokens/FlowMappingStartTokenTest.java @@ -0,0 +1,17 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.error.Mark;
+
+public class FlowMappingStartTokenTest extends TestCase {
+
+ public void testGetTokenId() {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ FlowMappingStartToken token = new FlowMappingStartToken(mark, mark);
+ assertEquals("{", token.getTokenId());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/tokens/FlowSequenceStartTokenTest.java b/src/test/java/org/yaml/snakeyaml/tokens/FlowSequenceStartTokenTest.java new file mode 100644 index 00000000..b79cbb97 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/tokens/FlowSequenceStartTokenTest.java @@ -0,0 +1,17 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.error.Mark;
+
+public class FlowSequenceStartTokenTest extends TestCase {
+
+ public void testGetTokenId() {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ FlowSequenceStartToken token = new FlowSequenceStartToken(mark, mark);
+ assertEquals("[", token.getTokenId());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/tokens/StreamStartTokenTest.java b/src/test/java/org/yaml/snakeyaml/tokens/StreamStartTokenTest.java new file mode 100644 index 00000000..8475e4ed --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/tokens/StreamStartTokenTest.java @@ -0,0 +1,17 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.error.Mark;
+
+public class StreamStartTokenTest extends TestCase {
+
+ public void testGetTokenId() {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ StreamStartToken token = new StreamStartToken(mark, mark);
+ assertEquals("<stream start>", token.getTokenId());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/tokens/TagTokenTest.java b/src/test/java/org/yaml/snakeyaml/tokens/TagTokenTest.java new file mode 100644 index 00000000..7ab3bb11 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/tokens/TagTokenTest.java @@ -0,0 +1,33 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.tokens;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.error.Mark;
+
+public class TagTokenTest extends TestCase {
+
+ public void testGetArguments() {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ TagToken token = new TagToken(new String[] { "!foo", "!bar" }, mark, mark);
+ assertEquals("value=[!foo, !bar]", token.getArguments());
+ }
+
+ public void testNoTag() {
+ try {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ new TagToken(new String[] { "!foo" }, mark, mark);
+ fail("Marks must be provided.");
+ } catch (Exception e) {
+ assertEquals("Two strings must be provided instead of 1", e.getMessage());
+ }
+ }
+
+ public void testGetTokenId() {
+ Mark mark = new Mark("test1", 0, 0, 0, "*The first line.\nThe last line.", 0);
+ TagToken token = new TagToken(new String[] { "!foo", "!bar" }, mark, mark);
+ assertEquals("<tag>", token.getTokenId());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/types/AbstractTest.java b/src/test/java/org/yaml/snakeyaml/types/AbstractTest.java new file mode 100644 index 00000000..0b464fb3 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/types/AbstractTest.java @@ -0,0 +1,36 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.types;
+
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+
+public abstract class AbstractTest extends TestCase {
+ @SuppressWarnings("unchecked")
+ protected Map<String, Object> getMap(String data) {
+ Yaml yaml = new Yaml();
+ Map<String, Object> nativeData = (Map<String, Object>) yaml.load(data);
+ return nativeData;
+ }
+
+ protected Object load(String data) {
+ Yaml yaml = new Yaml();
+ Object obj = yaml.load(data);
+ return obj;
+ }
+
+ protected String dump(Object data) {
+ Yaml yaml = new Yaml();
+ return yaml.dump(data);
+ }
+
+ @SuppressWarnings("unchecked")
+ protected Object getMapValue(String data, String key) {
+ Map nativeData = getMap(data);
+ return nativeData.get(key);
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/types/BinaryTagTest.java b/src/test/java/org/yaml/snakeyaml/types/BinaryTagTest.java new file mode 100644 index 00000000..8dcbecc3 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/types/BinaryTagTest.java @@ -0,0 +1,64 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.types;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @see http://yaml.org/type/binary.html
+ */
+public class BinaryTagTest extends AbstractTest {
+ String line1 = "R0lGODlhDAAMAIQAAP//9/X17unp5WZmZgAAAOfn515eXvPz7Y6OjuDg4J+fn5";
+ String line2 = "OTk6enp56enmlpaWNjY6Ojo4SEhP/++f/++f/++f/++f/++f/++f/++f/++f/+";
+ String line3 = "+f/++f/++f/++f/++f/++SH+Dk1hZGUgd2l0aCBHSU1QACwAAAAADAAMAAAFLC";
+ String line4 = "AgjoEwnuNAFOhpEMTRiggcz4BNJHrv/zCFcLiwMWYNG84BwwEeECcgggoBADs=";
+ String content = line1 + line2 + line3 + line4;
+
+ public void testBinary() throws IOException {
+ byte[] binary = (byte[]) getMapValue("canonical: !!binary " + content, "canonical");
+ assertEquals((byte) 'G', binary[0]);
+ assertEquals((byte) 'I', binary[1]);
+ assertEquals((byte) 'F', binary[2]);
+ assertEquals((byte) '8', binary[3]);
+ assertEquals((byte) '9', binary[4]);
+ }
+
+ public void testBinary2() throws IOException {
+ byte[] binary = (byte[]) load("!!binary \"MQ==\"");
+ assertEquals(1, binary.length);
+ assertEquals((byte) '1', binary[0]);
+ }
+
+ public void testBinaryTag() throws IOException {
+ byte[] binary = (byte[]) getMapValue("canonical: !<tag:yaml.org,2002:binary> " + content,
+ "canonical");
+ assertEquals((byte) 'G', binary[0]);
+ assertEquals((byte) 'I', binary[1]);
+ assertEquals((byte) 'F', binary[2]);
+ assertEquals((byte) '8', binary[3]);
+ assertEquals((byte) '9', binary[4]);
+ }
+
+ public void testBinaryOut() throws IOException {
+ byte[] data = "GIF89\tbi\u0003\u0000nary\n\u001Fimage\n".getBytes("ISO-8859-1");
+ Map<String, String> map = new HashMap<String, String>();
+ String value = new String(data, "ISO-8859-1");
+ map.put("canonical", value);
+ String output = dump(map);
+ assertEquals("canonical: !!binary |-\n R0lGODkJYmkDAG5hcnkKH2ltYWdlCg==\n", output);
+ }
+
+ public void testByteArray() throws IOException {
+ byte[] data = { 8, 14, 15, 10, 126, 32, 65, 65, 65 };
+ String output = dump(data);
+ assertEquals("!!binary |-\n CA4PCn4gQUFB\n", output);
+ byte[] parsed = (byte[]) load(output);
+ assertEquals(data.length, parsed.length);
+ for (int i = 0; i < data.length; i++) {
+ assertEquals(data[i], parsed[i]);
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/types/BoolTagTest.java b/src/test/java/org/yaml/snakeyaml/types/BoolTagTest.java new file mode 100644 index 00000000..68a1cd08 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/types/BoolTagTest.java @@ -0,0 +1,59 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.types;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @see http://yaml.org/type/int.html
+ */
+public class BoolTagTest extends AbstractTest {
+ public void testBool() throws IOException {
+ assertEquals(Boolean.TRUE, getMapValue("canonical: true", "canonical"));
+ assertEquals(Boolean.FALSE, getMapValue("answer: NO", "answer"));
+ assertEquals(Boolean.TRUE, getMapValue("logical: True", "logical"));
+ assertEquals(Boolean.TRUE, getMapValue("option: on", "option"));
+ }
+
+ public void testBoolCanonical() throws IOException {
+ assertEquals(Boolean.TRUE, getMapValue("canonical: Yes", "canonical"));
+ assertEquals(Boolean.TRUE, getMapValue("canonical: yes", "canonical"));
+ assertEquals(Boolean.TRUE, getMapValue("canonical: YES", "canonical"));
+ assertEquals("yES", getMapValue("canonical: yES", "canonical"));
+ assertEquals(Boolean.FALSE, getMapValue("canonical: No", "canonical"));
+ assertEquals(Boolean.FALSE, getMapValue("canonical: NO", "canonical"));
+ assertEquals(Boolean.FALSE, getMapValue("canonical: no", "canonical"));
+ assertEquals(Boolean.FALSE, getMapValue("canonical: off", "canonical"));
+ assertEquals(Boolean.FALSE, getMapValue("canonical: Off", "canonical"));
+ assertEquals(Boolean.FALSE, getMapValue("canonical: OFF", "canonical"));
+ assertEquals(Boolean.TRUE, getMapValue("canonical: ON", "canonical"));
+ assertEquals(Boolean.TRUE, getMapValue("canonical: On", "canonical"));
+ assertEquals(Boolean.TRUE, getMapValue("canonical: on", "canonical"));
+ // it looks like it is against the specification but it is like in
+ // PyYAML
+ assertEquals("n", getMapValue("canonical: n", "canonical"));
+ assertEquals("N", getMapValue("canonical: N", "canonical"));
+ assertEquals("y", getMapValue("canonical: y", "canonical"));
+ assertEquals("Y", getMapValue("canonical: Y", "canonical"));
+ }
+
+ public void testBoolShorthand() throws IOException {
+ assertEquals(Boolean.TRUE, getMapValue("boolean: !!bool true", "boolean"));
+ }
+
+ public void testBoolTag() throws IOException {
+ assertEquals(Boolean.TRUE,
+ getMapValue("boolean: !<tag:yaml.org,2002:bool> true", "boolean"));
+ }
+
+ public void testBoolOut() throws IOException {
+ Map<String, Boolean> map = new HashMap<String, Boolean>();
+ map.put("boolean", Boolean.TRUE);
+ String output = dump(map);
+ assertTrue(output, output.contains("boolean: true"));
+ }
+
+}
diff --git a/src/test/java/org/yaml/snakeyaml/types/FloatTagTest.java b/src/test/java/org/yaml/snakeyaml/types/FloatTagTest.java new file mode 100644 index 00000000..aa3ede81 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/types/FloatTagTest.java @@ -0,0 +1,55 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.types;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @see http://yaml.org/type/float.html
+ */
+public class FloatTagTest extends AbstractTest {
+
+ public void testFloat() throws IOException {
+ assertEquals(new Double(6.8523015e+5), getMapValue("canonical: 6.8523015e+5", "canonical"));
+ assertEquals(new Double(6.8523015e+5), getMapValue("exponentioal: 685.230_15e+03",
+ "exponentioal"));
+ assertEquals(new Double(6.8523015e+5), getMapValue("fixed: 685_230.15", "fixed"));
+ assertEquals(new Double(6.8523015e+5), getMapValue("sexagesimal: 190:20:30.15",
+ "sexagesimal"));
+ assertEquals(Double.NEGATIVE_INFINITY, getMapValue("negative infinity: -.inf",
+ "negative infinity"));
+ assertEquals(Double.NaN, getMapValue("not a number: .NaN", "not a number"));
+ }
+
+ public void testFloatShorthand() throws IOException {
+ assertEquals(new Double(1), getMapValue("number: !!float 1", "number"));
+ }
+
+ public void testFloatTag() throws IOException {
+ assertEquals(new Double(1), getMapValue("number: !<tag:yaml.org,2002:float> 1", "number"));
+ }
+
+ public void testFloatOut() throws IOException {
+ Map<String, Object> map = new HashMap<String, Object>();
+ map.put("number", new Double(1));
+ String output = dump(map);
+ assertEquals("{number: 1.0}\n", output);
+ }
+
+ public void testBasicDoubleScalarLoad() {
+ assertEquals(new Double(47.0), load("47.0"));
+ assertEquals(new Double(0.0), load("0.0"));
+ assertEquals(new Double(-1.0), load("-1.0"));
+ }
+
+ public void testDumpStr() {
+ assertEquals("'1.0'\n", dump("1.0"));
+ }
+
+ public void testDump() {
+ assertEquals("1.0\n", dump(1.0));
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/types/IntTagTest.java b/src/test/java/org/yaml/snakeyaml/types/IntTagTest.java new file mode 100644 index 00000000..d75dad32 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/types/IntTagTest.java @@ -0,0 +1,55 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.types;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @see http://yaml.org/type/int.html
+ */
+public class IntTagTest extends AbstractTest {
+
+ public void testInt() throws IOException {
+ assertEquals(new Integer(685230), getMapValue("canonical: 685230", "canonical"));
+ assertEquals(new Integer(685230), getMapValue("number: 685_230", "number"));
+ assertEquals(new Integer(685230), getMapValue("decimal: +685230", "decimal"));
+ assertEquals(new Integer(-685230), getMapValue("number: -685230", "number"));
+ assertEquals(new Integer(685230), getMapValue("octal: 02472256", "octal"));
+ assertEquals(new Integer(685230), getMapValue("hexadecimal: 0x_0A_74_AE", "hexadecimal"));
+ assertEquals(new Integer(685230), getMapValue("binary: 0b1010_0111_0100_1010_1110",
+ "binary"));
+ assertEquals(new Integer(685230), getMapValue("sexagesimal: 190:20:30", "sexagesimal"));
+ assertEquals(new Integer(0), load("0"));
+ assertEquals(new Integer(0), load("-0"));
+ assertEquals(new Integer(0), load("+0"));
+ assertEquals(Integer.MIN_VALUE, load(dump(Integer.MIN_VALUE)));
+ assertEquals(Integer.MAX_VALUE, load(dump(Integer.MAX_VALUE)));
+ }
+
+ public void testBigInt() throws IOException {
+ assertEquals(new Long(922337203685477580L), load("922337203685477580"));
+ assertEquals(new BigInteger("9223372036854775809999999999"),
+ load("9223372036854775809999999999"));
+ assertEquals(Long.MIN_VALUE, load("-9223372036854775808"));
+ }
+
+ public void testIntShorthand() throws IOException {
+ assertEquals(new Integer(1), getMapValue("number: !!int 1", "number"));
+ }
+
+ public void testIntTag() throws IOException {
+ assertEquals(new Integer(1), getMapValue("number: !<tag:yaml.org,2002:int> 1", "number"));
+ }
+
+ public void testIntOut() throws IOException {
+ Map<String, Integer> map = new HashMap<String, Integer>();
+ map.put("number", new Integer(1));
+ String output = dump(map);
+ assertTrue(output.contains("number: 1"));
+ }
+
+}
diff --git a/src/test/java/org/yaml/snakeyaml/types/MapTagTest.java b/src/test/java/org/yaml/snakeyaml/types/MapTagTest.java new file mode 100644 index 00000000..5977c7e0 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/types/MapTagTest.java @@ -0,0 +1,59 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.types;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.yaml.snakeyaml.YamlDocument;
+
+/**
+ * @see http://yaml.org/type/map.html
+ */
+public class MapTagTest extends AbstractTest {
+
+ @SuppressWarnings("unchecked")
+ public void testMap() throws IOException {
+ YamlDocument document = new YamlDocument("types/map.yaml");
+ Map<String, Map<String, String>> map = (Map<String, Map<String, String>>) document
+ .getNativeData();
+ assertEquals(2, map.size());
+ Map<String, String> map1 = (Map<String, String>) map.get("Block style");
+ assertEquals(3, map1.size());
+ assertEquals("Evans", map1.get("Clark"));
+ assertEquals("Ingerson", map1.get("Brian"));
+ assertEquals("Ben-Kiki", map1.get("Oren"));
+ //
+ Map<String, String> map2 = (Map<String, String>) map.get("Flow style");
+ assertEquals(3, map2.size());
+ assertEquals("Evans", map2.get("Clark"));
+ assertEquals("Ingerson", map2.get("Brian"));
+ assertEquals("Ben-Kiki", map2.get("Oren"));
+ //
+ assertEquals(map1, map2);
+ assertNotSame(map1, map2);
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testMapYaml11() throws IOException {
+ YamlDocument document = new YamlDocument("types/map_mixed_tags.yaml");
+ Map<String, Map<String, String>> map = (Map<String, Map<String, String>>) document
+ .getNativeData();
+ assertEquals(2, map.size());
+ Map<String, String> map1 = (Map<String, String>) map.get("Block style");
+ assertEquals(3, map1.size());
+ assertEquals("Evans", map1.get("Clark"));
+ assertEquals("Ingerson", map1.get("Brian"));
+ assertEquals("Ben-Kiki", map1.get("Oren"));
+ //
+ Map<String, String> map2 = (Map<String, String>) map.get("Flow style");
+ assertEquals(3, map2.size());
+ assertEquals("Evans", map2.get("Clark"));
+ assertEquals("Ingerson", map2.get("Brian"));
+ assertEquals("Ben-Kiki", map2.get("Oren"));
+ //
+ assertEquals(map1, map2);
+ }
+
+}
diff --git a/src/test/java/org/yaml/snakeyaml/types/MergeTagTest.java b/src/test/java/org/yaml/snakeyaml/types/MergeTagTest.java new file mode 100644 index 00000000..1805d201 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/types/MergeTagTest.java @@ -0,0 +1,59 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.types;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+import org.yaml.snakeyaml.YamlDocument;
+
+/**
+ * @see http://yaml.org/type/merge.html
+ */
+public class MergeTagTest extends AbstractTest {
+
+ @SuppressWarnings("unchecked")
+ public void testMerge() throws IOException {
+ YamlDocument document = new YamlDocument("types/merge.yaml");
+ List list = (List) document.getNativeData();
+ assertEquals(8, list.size());
+ Map<Object, Object> center = (Map<Object, Object>) list.get(0);
+ assertEquals(2, center.size());
+ assertEquals(new Integer(1), center.get("x"));
+ assertEquals(new Integer(2), center.get("y"));
+ //
+ Map<Object, Object> left = (Map<Object, Object>) list.get(1);
+ assertEquals(2, left.size());
+ assertEquals(left.get("x").getClass().toString(), new Integer(0), left.get("x"));
+ assertEquals(new Integer(2), left.get("y"));
+ //
+ Map<Object, Object> big = (Map<Object, Object>) list.get(2);
+ assertEquals(1, big.size());
+ assertEquals(new Integer(10), big.get("r"));
+ //
+ Map<Object, Object> small = (Map<Object, Object>) list.get(3);
+ assertEquals(1, small.size());
+ assertEquals(new Integer(1), small.get("r"));
+ // Explicit keys
+ Map<Object, Object> explicit = (Map<Object, Object>) list.get(4);
+ assertEquals(4, explicit.size());
+ assertEquals(new Integer(1), explicit.get("x"));
+ assertEquals(new Integer(2), explicit.get("y"));
+ assertEquals(new Integer(10), explicit.get("r"));
+ assertEquals("center/big", explicit.get("label"));
+ // Merge one map
+ Map<Object, Object> merged1 = (Map<Object, Object>) list.get(5);
+ assertEquals(explicit, merged1);
+ assertNotSame(explicit, merged1);
+ // Merge multiple maps
+ Map<Object, Object> merged2 = (Map<Object, Object>) list.get(6);
+ assertEquals(explicit, merged2);
+ assertNotSame(explicit, merged2);
+ // Override
+ Map<Object, Object> merged3 = (Map<Object, Object>) list.get(7);
+ assertEquals(explicit, merged3);
+ assertNotSame(explicit, merged3);
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/types/NullTagTest.java b/src/test/java/org/yaml/snakeyaml/types/NullTagTest.java new file mode 100644 index 00000000..d874691e --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/types/NullTagTest.java @@ -0,0 +1,73 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.types;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @see http://yaml.org/type/null.html
+ */
+public class NullTagTest extends AbstractTest {
+
+ public void testNull() throws IOException {
+ assertNull("Got: '" + load("---\n") + "'", load("---\n"));
+ assertNull(load("---\n..."));
+ assertNull(load("---\n...\n"));
+ assertNull(load("\n"));
+ assertNull(load(""));
+ assertNull(load(" "));
+ assertNull(load("~"));
+ assertNull(load("---\n~"));
+ assertNull(load("null"));
+ assertNull(load("Null"));
+ assertNull(load("NULL"));
+ assertNull(getMapValue("empty:\n", "empty"));
+ assertNull(getMapValue("canonical: ~", "canonical"));
+ assertNull(getMapValue("english: null", "english"));
+ assertNull(getMapValue("english: Null", "english"));
+ assertNull(getMapValue("english: NULL", "english"));
+ assertEquals("null key", getMapValue("~: null key\n", null));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testSequenceNull() throws IOException {
+ String input = "---\n# This sequence has five\n# entries, two have values.\nsparse:\n - ~\n - 2nd entry\n -\n - 4th entry\n - Null\n";
+ List<String> parsed = (List<String>) getMapValue(input, "sparse");
+ assertEquals(5, parsed.size());
+ assertNull(parsed.get(0));
+ assertEquals("2nd entry", parsed.get(1));
+ assertNull("Got: '" + parsed.get(2) + "'", parsed.get(2));
+ assertEquals("4th entry", parsed.get(3));
+ assertNull(parsed.get(4));
+ }
+
+ public void testNullInMap() throws IOException {
+ String input = "key1: null\n~: value1";
+ Map<String, Object> parsed = getMap(input);
+ assertEquals(2, parsed.size());
+ assertTrue(parsed.containsKey(null));
+ Object value1 = parsed.get(null);
+ assertEquals("value1", value1);
+ //
+ assertNull(parsed.get("key1"));
+ //
+ assertFalse(getMap("key2: value2").containsKey(null));
+ }
+
+ public void testBoolShorthand() throws IOException {
+ assertNull(getMapValue("nothing: !!null null", "nothing"));
+ }
+
+ public void testBoolTag() throws IOException {
+ assertNull(getMapValue("nothing: !<tag:yaml.org,2002:null> null", "nothing"));
+ }
+
+ public void testBoolOut() throws IOException {
+ String output = dump(null);
+ assertEquals("null\n", output);
+ }
+
+}
diff --git a/src/test/java/org/yaml/snakeyaml/types/OmapTagTest.java b/src/test/java/org/yaml/snakeyaml/types/OmapTagTest.java new file mode 100644 index 00000000..4af21425 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/types/OmapTagTest.java @@ -0,0 +1,35 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.types;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.yaml.snakeyaml.YamlDocument;
+
+/**
+ * @see http://yaml.org/type/omap.html
+ */
+public class OmapTagTest extends AbstractTest {
+
+ @SuppressWarnings("unchecked")
+ public void testOmap() throws IOException {
+ YamlDocument document = new YamlDocument("types/omap.yaml");
+ Map<String, Map<String, String>> map = (Map<String, Map<String, String>>) document
+ .getNativeData();
+ assertEquals(2, map.size());
+ Map<String, String> map1 = (Map<String, String>) map.get("Bestiary");
+ assertEquals(3, map1.size());
+ assertEquals("African pig-like ant eater. Ugly.", map1.get("aardvark"));
+ assertEquals("South-American ant eater. Two species.", map1.get("anteater"));
+ assertEquals("South-American constrictor snake. Scaly.", map1.get("anaconda"));
+ //
+ Map<String, String> map2 = (Map<String, String>) map.get("Numbers");
+ assertEquals(3, map2.size());
+ assertEquals(new Integer(1), map2.get("one"));
+ assertEquals(new Integer(2), map2.get("two"));
+ assertEquals(new Integer(3), map2.get("three"));
+ }
+
+}
diff --git a/src/test/java/org/yaml/snakeyaml/types/PairsTagTest.java b/src/test/java/org/yaml/snakeyaml/types/PairsTagTest.java new file mode 100644 index 00000000..e03b3a6a --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/types/PairsTagTest.java @@ -0,0 +1,59 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.types;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+import org.yaml.snakeyaml.YamlDocument;
+
+/**
+ * @see http://yaml.org/type/pairs.html
+ */
+public class PairsTagTest extends AbstractTest {
+
+ @SuppressWarnings("unchecked")
+ public void testPairs() throws IOException {
+ YamlDocument document = new YamlDocument("types/pairs.yaml", false);
+ Map<String, List<String[]>> map = (Map<String, List<String[]>>) document.getNativeData();
+ assertEquals(2, map.size());
+ List<String[]> list1 = (List<String[]>) map.get("Block tasks");
+ assertEquals(4, list1.size());
+ Object[] tuple1 = list1.get(0);
+ assertEquals(2, tuple1.length);
+ assertEquals("meeting", tuple1[0]);
+ assertEquals("with team.", tuple1[1]);
+ //
+
+ Object[] tuple2 = list1.get(1);
+ assertEquals(2, tuple2.length);
+ assertEquals("meeting", tuple2[0]);
+ assertEquals("with boss.", tuple2[1]);
+ //
+
+ Object[] tuple3 = list1.get(2);
+ assertEquals(2, tuple3.length);
+ assertEquals("break", tuple3[0]);
+ assertEquals("lunch.", tuple3[1]);
+ //
+
+ Object[] tuple4 = list1.get(3);
+ assertEquals(2, tuple4.length);
+ assertEquals("meeting", tuple4[0]);
+ assertEquals("with client.", tuple4[1]);
+ //
+ List<String[]> list2 = (List<String[]>) map.get("Flow tasks");
+ assertEquals(2, list2.size());
+ Object[] tuple2_1 = list2.get(0);
+ assertEquals(2, tuple2_1.length);
+ assertEquals("meeting", tuple2_1[0]);
+ assertEquals("with team", tuple2_1[1]);
+ //
+ Object[] tuple2_2 = list2.get(1);
+ assertEquals(2, tuple2_2.length);
+ assertEquals("meeting", tuple2_2[0]);
+ assertEquals("with boss", tuple2_2[1]);
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/types/SeqTagTest.java b/src/test/java/org/yaml/snakeyaml/types/SeqTagTest.java new file mode 100644 index 00000000..0b142eed --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/types/SeqTagTest.java @@ -0,0 +1,70 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.types;
+
+import java.util.List;
+import java.util.Map;
+
+import org.yaml.snakeyaml.YamlDocument;
+
+/**
+ * @see http://yaml.org/type/seq.html
+ */
+public class SeqTagTest extends AbstractTest {
+
+ @SuppressWarnings("unchecked")
+ public void testSeq() {
+ YamlDocument document = new YamlDocument("types/seq.yaml");
+ Map<String, List<String>> map = (Map<String, List<String>>) document.getNativeData();
+ assertEquals(2, map.size());
+ List<String> list1 = (List<String>) map.get("Block style");
+ assertEquals(9, list1.size());
+ assertEquals("Mercury", list1.get(0));
+ assertEquals("Venus", list1.get(1));
+ assertEquals("Earth", list1.get(2));
+ assertEquals("Mars", list1.get(3));
+ assertEquals("Jupiter", list1.get(4));
+ assertEquals("Saturn", list1.get(5));
+ assertEquals("Uranus", list1.get(6));
+ assertEquals("Neptune", list1.get(7));
+ assertEquals("Pluto", list1.get(8));
+ //
+ List<String> list2 = (List<String>) map.get("Flow style");
+ assertEquals(9, list2.size());
+ assertEquals("Mercury", list2.get(0));
+ assertEquals("Venus", list2.get(1));
+ assertEquals("Earth", list2.get(2));
+ assertEquals("Mars", list2.get(3));
+ assertEquals("Jupiter", list2.get(4));
+ assertEquals("Saturn", list2.get(5));
+ assertEquals("Uranus", list2.get(6));
+ assertEquals("Neptune", list2.get(7));
+ assertEquals("Pluto", list2.get(8));
+ //
+ assertEquals(list1, list2);
+ assertNotSame(list1, list2);
+ }
+
+ public void testArray() {
+ Integer[] array = new Integer[3];
+ array[0] = new Integer(1);
+ array[1] = new Integer(1);
+ array[2] = new Integer(2);
+ String output = dump(array);
+ assertEquals("[1, 1, 2]\n", output);
+ }
+
+ public void testArrayPrimitives() {
+ int[] array = new int[3];
+ array[0] = 1;
+ array[1] = 1;
+ array[2] = 2;
+ try {
+ dump(array);
+ fail("Arrays of primitives are not supported.");
+ } catch (RuntimeException e) {
+ assertEquals("Arrays of primitives are not fully supported.", e.getMessage());
+ }
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/types/SetTagTest.java b/src/test/java/org/yaml/snakeyaml/types/SetTagTest.java new file mode 100644 index 00000000..ea0acbdc --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/types/SetTagTest.java @@ -0,0 +1,33 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.types;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.yaml.snakeyaml.YamlDocument;
+
+/**
+ * @see http://yaml.org/type/set.html
+ */
+public class SetTagTest extends AbstractTest {
+
+ @SuppressWarnings("unchecked")
+ public void testSet() {
+ YamlDocument document = new YamlDocument("types/set.yaml");
+ Map<String, Set<String>> map = (Map<String, Set<String>>) document.getNativeData();
+ assertEquals(2, map.size());
+ Set<String> set1 = (Set<String>) map.get("baseball players");
+ assertEquals(3, set1.size());
+ assertTrue(set1.contains("Mark McGwire"));
+ assertTrue(set1.contains("Sammy Sosa"));
+ assertTrue(set1.contains("Ken Griffey"));
+ //
+ Set<String> set2 = (Set<String>) map.get("baseball teams");
+ assertEquals(3, set2.size());
+ assertTrue(set2.contains("Boston Red Sox"));
+ assertTrue(set2.contains("Detroit Tigers"));
+ assertTrue(set2.contains("New York Yankees"));
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/types/StrTagTest.java b/src/test/java/org/yaml/snakeyaml/types/StrTagTest.java new file mode 100644 index 00000000..c2ebcd60 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/types/StrTagTest.java @@ -0,0 +1,130 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.types;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.nio.charset.Charset;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.yaml.snakeyaml.Yaml;
+
+/**
+ * @see http://yaml.org/type/str.html
+ */
+public class StrTagTest extends AbstractTest {
+ private String getData(String data, String key) {
+ return (String) getMapValue(data, key);
+ }
+
+ public void testString() throws IOException {
+ assertEquals("abcd", getData("string: abcd", "string"));
+ }
+
+ public void testStringShorthand() throws IOException {
+ assertEquals("abcd", getData("string: !!str abcd", "string"));
+ }
+
+ public void testStringTag() throws IOException {
+ assertEquals("abcd", getData("string: !<tag:yaml.org,2002:str> abcd", "string"));
+ }
+
+ public void testUnicode() throws IOException {
+ // escaped 8-bit unicode character (u-umlaut):
+ assertEquals("\u00fc", load("\"\\xfc\""));
+ assertEquals("\\xfc", load("\\xfc"));
+
+ // 2 escaped 8-bit unicode characters (u-umlaut following by e-grave):
+ assertEquals("\u00fc\u00e8", load("\"\\xfc\\xe8\""));
+
+ // escaped 16-bit unicode character (em dash):
+ assertEquals("\u2014", load("\"\\u2014\""));
+
+ // UTF-32 encoding is explicitly not supported
+ assertEquals("\\U2014AAAA", load("'\\U2014AAAA'"));
+
+ // (and I don't have a surrogate pair handy at the moment)
+ // raw unicode characters in the stream (em dash)
+ assertEquals("\u2014", load("\u2014"));
+ }
+
+ /**
+ * @see http://code.google.com/p/jvyamlb/issues/detail?id=6
+ */
+ @SuppressWarnings("unchecked")
+ public void testIssueId6() {
+ Map<String, String> map = (Map<String, String>) load("---\ntest: |-\n \"Test\r\r (* error here)\"");
+ assertEquals("\"Test\n\n(* error here)\"", map.get("test"));
+ }
+
+ public void testStrDump() {
+ assertEquals("abc\n", dump("abc"));
+ }
+
+ public void testUnicodeDump() {
+ assertEquals("\\u263a\n", dump("\\u263a"));
+ assertEquals("The leading zero must be preserved.", "\\u063a\n", dump("\\u063a"));
+ }
+
+ public void testStringIntOut() {
+ Map<String, String> map = new HashMap<String, String>();
+ map.put("number", "1");
+ String output = dump(map);
+ assertTrue(output, output.contains("number: '1'"));
+ }
+
+ public void testStringFloatOut() {
+ Map<String, String> map = new HashMap<String, String>();
+ map.put("number", "1.1");
+ String output = dump(map);
+ assertTrue(output, output.contains("number: '1.1'"));
+ }
+
+ public void testStringBoolOut() {
+ Map<String, String> map = new HashMap<String, String>();
+ map.put("number", "True");
+ String output = dump(map);
+ assertTrue(output, output.contains("number: 'True'"));
+ }
+
+ public void testEmitLongString() throws IOException {
+ String str = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
+ String output = dump(str);
+ assertEquals(str + "\n", output);
+ }
+
+ public void testEmitLongStringWithCR() throws IOException {
+ String str = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n\n";
+ String output = dump(str);
+ assertEquals("'" + str + "\n '\n", output);
+ }
+
+ public void testEmitDoubleQuoted() throws IOException {
+ String str = "\"xx\"";
+ String output = dump(str);
+ assertEquals("'" + str + "'\n", output);
+ }
+
+ public void testEmitEndOfLine() throws IOException {
+ String str = "xxxxxxx\n";
+ String output = dump(str);
+ assertEquals("'" + str + "\n '\n", output);
+ }
+
+ public void testDumpUtf16() throws IOException {
+ String str = "xxx";
+ assertEquals(3, str.toString().length());
+ Yaml yaml = new Yaml();
+ Charset charset = Charset.forName("UTF-16");
+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ Writer writer = new OutputStreamWriter(stream, charset);
+ yaml.dump(str, writer);
+ assertEquals(str + "\n", stream.toString("UTF-16"));
+ assertEquals("Must include BOM: " + stream.toString(), (1 + 3 + 1) * 2, stream.toString()
+ .length());
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/types/TimestampTagTest.java b/src/test/java/org/yaml/snakeyaml/types/TimestampTagTest.java new file mode 100644 index 00000000..9135c046 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/types/TimestampTagTest.java @@ -0,0 +1,93 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.types;
+
+import java.io.IOException;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.TimeZone;
+
+/**
+ * @see http://yaml.org/type/timestamp.html
+ */
+public class TimestampTagTest extends AbstractTest {
+
+ public void testTimestamp() throws IOException {
+ assertEquals("2001-12-15 at 2:59:43 (100)", getText("canonical: 2001-12-15T02:59:43.1Z",
+ "canonical"));
+ assertEquals("2001-12-15 at 2:59:43 (100)", getText(
+ "valid iso8601: 2001-12-14t21:59:43.10-05:00", "valid iso8601"));
+ assertEquals("2001-12-15 at 2:59:43 (100)", getText(
+ "space separated: 2001-12-14 21:59:43.10 -5", "space separated"));
+ assertEquals("2001-12-15 at 2:59:43 (100)", getText(
+ "no time zone (Z): 2001-12-15 2:59:43.10", "no time zone (Z)"));
+ assertEquals("2002-12-14 at 0:0:0 (0)", getText("date (00:00:00Z): 2002-12-14",
+ "date (00:00:00Z)"));
+ }
+
+ public void testTimestampShorthand() throws IOException {
+ assertTrue(getMapValue("canonical: !!timestamp 2001-12-15T02:59:43.1Z", "canonical") instanceof Date);
+ }
+
+ public void testTimestampTag() throws IOException {
+ assertTrue(getMapValue("canonical: !<tag:yaml.org,2002:timestamp> 2001-12-15T02:59:43.1Z",
+ "canonical") instanceof Date);
+ }
+
+ public void testTimestampOut() throws IOException {
+ Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("Europe/Moscow"));
+ cal.clear();
+ cal.set(2008, 8, 23, 14, 35, 4);
+ Date date = cal.getTime();
+ String output = dump(date);
+ assertEquals("2008-09-23T10:35:04Z\n", output);
+ }
+
+ public void testTimestampOutMap() throws IOException {
+ Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("Europe/Moscow"));
+ cal.clear();
+ cal.set(2008, 8, 23, 14, 35, 4);
+ Date date = cal.getTime();
+ Map<String, Date> map = new HashMap<String, Date>();
+ map.put("canonical", date);
+ String output = dump(map);
+ assertEquals("{canonical: !!timestamp '2008-09-23T10:35:04Z'}\n", output);
+ }
+
+ private String getText(String yaml, String key) {
+ Date date = (Date) getMapValue(yaml, key);
+ Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
+ cal.setTime(date);
+ int years = cal.get(Calendar.YEAR);
+ int months = cal.get(Calendar.MONTH) + 1; // 0..12
+ int days = cal.get(Calendar.DAY_OF_MONTH); // 1..31
+ int hour24 = cal.get(Calendar.HOUR_OF_DAY); // 0..24
+ int minutes = cal.get(Calendar.MINUTE); // 0..59
+ int seconds = cal.get(Calendar.SECOND); // 0..59
+ int millis = cal.get(Calendar.MILLISECOND);
+ String result = String.valueOf(years) + "-" + String.valueOf(months) + "-"
+ + String.valueOf(days) + " at " + String.valueOf(hour24) + ":"
+ + String.valueOf(minutes) + ":" + String.valueOf(seconds) + " ("
+ + String.valueOf(millis) + ")";
+ return result;
+ }
+
+ public void testTimestampReadWrite() throws IOException {
+ Date date = (Date) getMapValue("Time: 2001-11-23 15:01:42 -5", "Time");
+ Map<String, Date> map = new HashMap<String, Date>();
+ map.put("canonical", date);
+ String output = dump(map);
+ assertEquals("{canonical: !!timestamp '2001-11-23T20:01:42Z'}\n", output);
+ }
+
+ public void testSqlDate() throws IOException {
+ java.sql.Date date = new java.sql.Date(1000000000000L);
+ Map<String, java.sql.Date> map = new HashMap<String, java.sql.Date>();
+ map.put("canonical", date);
+ String output = dump(map);
+ assertEquals("{canonical: !!timestamp '2001-09-09T01:46:40Z'}\n", output);
+ }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/types/ValueTagTest.java b/src/test/java/org/yaml/snakeyaml/types/ValueTagTest.java new file mode 100644 index 00000000..a18a2e02 --- /dev/null +++ b/src/test/java/org/yaml/snakeyaml/types/ValueTagTest.java @@ -0,0 +1,49 @@ +/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.types;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.YamlDocument;
+
+/**
+ * @see http://yaml.org/type/value.html
+ */
+public class ValueTagTest extends AbstractTest {
+
+ /**
+ * The 'value' tag does not work as defined in the specification but exactly
+ * as in PyYAML
+ */
+ @SuppressWarnings("unchecked")
+ public void testValue() throws IOException {
+ InputStream input = YamlDocument.class.getClassLoader().getResourceAsStream(
+ YamlDocument.ROOT + "types/value.yaml");
+ Yaml yaml = new Yaml();
+ Iterator iter = (Iterator) yaml.loadAll(input).iterator();
+ Map<String, List<String>> oldSchema = (Map<String, List<String>>) iter.next();
+ assertEquals(1, oldSchema.size());
+ List<String> list = oldSchema.get("link with");
+ assertEquals(2, list.size());
+ assertEquals("library1.dll", list.get(0));
+ assertEquals("library2.dll", list.get(1));
+ //
+ Map<String, List<Map<String, String>>> newSchema = (Map<String, List<Map<String, String>>>) iter
+ .next();
+ assertEquals(1, newSchema.size());
+ //
+ List<Map<String, String>> list2 = newSchema.get("link with");
+ assertEquals(2, list2.size());
+ Map<String, String> map1 = list2.get(0);
+ assertEquals(2, map1.size());
+ assertEquals("library1.dll", map1.get("="));
+ assertEquals(new Double(1.2), map1.get("version"));
+ assertFalse(iter.hasNext());
+ }
+}
diff --git a/src/test/resources/constructor/car-no-root-class-map.yaml b/src/test/resources/constructor/car-no-root-class-map.yaml new file mode 100644 index 00000000..a2b9f317 --- /dev/null +++ b/src/test/resources/constructor/car-no-root-class-map.yaml @@ -0,0 +1,15 @@ +plate: 00-FF-Q2
+wheels:
+ ? {brand: Pirelli, id: 1}
+ : 2008-01-16
+ ? {brand: Dunkel, id: 2}
+ : 2002-12-24
+ ? {brand: Pirelli, id: 3}
+ : 2008-01-16
+ ? {brand: Pirelli, id: 4}
+ : 2008-01-16
+ ? {brand: Pirelli, id: 5}
+ : 2008-01-16
+windows:
+ front: 0
+ back: 1
\ No newline at end of file diff --git a/src/test/resources/constructor/car-no-root-class.yaml b/src/test/resources/constructor/car-no-root-class.yaml new file mode 100644 index 00000000..a6451940 --- /dev/null +++ b/src/test/resources/constructor/car-no-root-class.yaml @@ -0,0 +1,8 @@ +# No root class defined
+plate: 12-XP-F4
+wheels:
+- {id: 1}
+- {id: 2}
+- {id: 3}
+- {id: 4}
+- {id: 5}
\ No newline at end of file diff --git a/src/test/resources/constructor/car-with-tags.yaml b/src/test/resources/constructor/car-with-tags.yaml new file mode 100644 index 00000000..2f7e823f --- /dev/null +++ b/src/test/resources/constructor/car-with-tags.yaml @@ -0,0 +1,8 @@ +!!org.yaml.snakeyaml.constructor.Car
+plate: 12-XP-F4
+wheels:
+- {id: 1}
+- {id: 2}
+- {id: 3}
+- {id: 4}
+- {id: 5}
\ No newline at end of file diff --git a/src/test/resources/constructor/car-without-root-tag.yaml b/src/test/resources/constructor/car-without-root-tag.yaml new file mode 100644 index 00000000..b91b184f --- /dev/null +++ b/src/test/resources/constructor/car-without-root-tag.yaml @@ -0,0 +1,5 @@ +map: {id: 3}
+part: null
+plate: 12-XP-F4
+wheel: {id: 2}
+year: '2008'
\ No newline at end of file diff --git a/src/test/resources/constructor/car-without-tags.yaml b/src/test/resources/constructor/car-without-tags.yaml new file mode 100644 index 00000000..20f5556a --- /dev/null +++ b/src/test/resources/constructor/car-without-tags.yaml @@ -0,0 +1,8 @@ +!car
+plate: 12-XP-F4
+wheels:
+- {id: 1}
+- {id: 2}
+- {id: 3}
+- {id: 4}
+- {id: 5}
\ No newline at end of file diff --git a/src/test/resources/constructor/cararray-with-tags.yaml b/src/test/resources/constructor/cararray-with-tags.yaml new file mode 100644 index 00000000..fed7cda5 --- /dev/null +++ b/src/test/resources/constructor/cararray-with-tags.yaml @@ -0,0 +1,8 @@ +!!org.yaml.snakeyaml.constructor.ArrayTagsTest$CarWithArray
+plate: 12-XP-F4
+wheels:
+- {id: 1}
+- {id: 2}
+- {id: 3}
+- {id: 4}
+- {id: 5}
\ No newline at end of file diff --git a/src/test/resources/constructor/carwheel-root-map.yaml b/src/test/resources/constructor/carwheel-root-map.yaml new file mode 100644 index 00000000..d7ea8857 --- /dev/null +++ b/src/test/resources/constructor/carwheel-root-map.yaml @@ -0,0 +1,3 @@ +wheel: !!org.yaml.snakeyaml.constructor.Wheel {id: 2}
+map: {id: 3}
+plate: 12-XP-F4
diff --git a/src/test/resources/constructor/carwheel-without-tags.yaml b/src/test/resources/constructor/carwheel-without-tags.yaml new file mode 100644 index 00000000..ab0ac449 --- /dev/null +++ b/src/test/resources/constructor/carwheel-without-tags.yaml @@ -0,0 +1,6 @@ +!!org.yaml.snakeyaml.constructor.ImplicitTagsTest$CarWithWheel
+map: {id: 3}
+part: !!org.yaml.snakeyaml.constructor.Wheel {id: 4}
+plate: 12-XP-F4
+wheel: {id: 2}
+year: '2008'
diff --git a/src/test/resources/constructor/test-primitives1.yaml b/src/test/resources/constructor/test-primitives1.yaml new file mode 100644 index 00000000..7403c37d --- /dev/null +++ b/src/test/resources/constructor/test-primitives1.yaml @@ -0,0 +1,23 @@ +# TestBean1
+byteClass: 1
+bytePrimitive: -3
+shortClass: +0
+shortPrimitive: -015 # octal
+integer: 5
+intPrimitive: 17
+text: the text
+id: 13
+longClass: 11111111111
+longPrimitive: 9999999999
+booleanClass: True
+booleanPrimitive: on
+charClass: 2
+charPrimitive: '#'
+bigInteger: 1234567890123456789012345678901234567890
+floatClass: 2
+floatPrimitive: 3.1416
+doubleClass: 4.0
+doublePrimitive: +1.12e4
+date: 2008-01-09
+publicField: public
+
diff --git a/src/test/resources/examples/any-object-example.yaml b/src/test/resources/examples/any-object-example.yaml new file mode 100644 index 00000000..2ba2be54 --- /dev/null +++ b/src/test/resources/examples/any-object-example.yaml @@ -0,0 +1,6 @@ +none: [~, null]
+bool: [true, false, on, off]
+int: 42
+float: 3.14159
+list: [LITE, RES_ACID, SUS_DEXT]
+dict: {hp: 13, sp: 5}
diff --git a/src/test/resources/examples/spring.xml b/src/test/resources/examples/spring.xml new file mode 100644 index 00000000..3d9a30c8 --- /dev/null +++ b/src/test/resources/examples/spring.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:util="http://www.springframework.org/schema/util" xmlns:p="http://www.springframework.org/schema/p"
+ xsi:schemaLocation="
+http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
+http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.0.xsd">
+
+ <!-- the most powerful way -->
+ <bean id="yamlConstructor" class="examples.CustomConstructor" scope="prototype" />
+ <bean id="yamlLoader" class="org.yaml.snakeyaml.Loader" scope="prototype">
+ <constructor-arg ref="yamlConstructor" />
+ </bean>
+ <bean id="yamlRepresenter" class="org.yaml.snakeyaml.representer.Representer" scope="prototype" />
+ <bean id="yamlOptions" class="org.yaml.snakeyaml.DumperOptions" scope="prototype">
+ <property name="indent" value="2" />
+ </bean>
+ <bean id="yamlDumper" class="org.yaml.snakeyaml.Dumper" scope="prototype">
+ <constructor-arg ref="yamlRepresenter" />
+ <constructor-arg ref="yamlOptions" />
+ </bean>
+ <bean id="snakeYaml" class="org.yaml.snakeyaml.Yaml" scope="prototype">
+ <constructor-arg ref="yamlLoader" />
+ <constructor-arg ref="yamlDumper" />
+ </bean>
+
+ <!-- for a single JavaBean -->
+ <bean id="beanConstructor" class="org.yaml.snakeyaml.constructor.Constructor" scope="prototype">
+ <constructor-arg value="org.yaml.snakeyaml.Invoice" />
+ </bean>
+ <bean id="beanLoader" class="org.yaml.snakeyaml.Loader" scope="prototype">
+ <constructor-arg ref="beanConstructor" />
+ </bean>
+ <bean id="javabeanYaml" class="org.yaml.snakeyaml.Yaml" scope="prototype">
+ <constructor-arg ref="beanLoader" />
+ </bean>
+
+ <!-- the simplest way -->
+ <bean id="standardYaml" class="org.yaml.snakeyaml.Yaml" scope="prototype" />
+</beans>
\ No newline at end of file diff --git a/src/test/resources/pyyaml/a-nasty-libyaml-bug.loader-error b/src/test/resources/pyyaml/a-nasty-libyaml-bug.loader-error new file mode 100644 index 00000000..f97d49f8 --- /dev/null +++ b/src/test/resources/pyyaml/a-nasty-libyaml-bug.loader-error @@ -0,0 +1 @@ +[ [
\ No newline at end of file diff --git a/src/test/resources/pyyaml/aliases.events b/src/test/resources/pyyaml/aliases.events new file mode 100644 index 00000000..9139b515 --- /dev/null +++ b/src/test/resources/pyyaml/aliases.events @@ -0,0 +1,8 @@ +- !StreamStart +- !DocumentStart +- !SequenceStart +- !Scalar { anchor: 'myanchor', tag: '!mytag', value: 'data' } +- !Alias { anchor: 'myanchor' } +- !SequenceEnd +- !DocumentEnd +- !StreamEnd diff --git a/src/test/resources/pyyaml/bool.data b/src/test/resources/pyyaml/bool.data new file mode 100644 index 00000000..0988b631 --- /dev/null +++ b/src/test/resources/pyyaml/bool.data @@ -0,0 +1,4 @@ +- yes +- NO +- True +- on diff --git a/src/test/resources/pyyaml/colon-in-flow-context.loader-error b/src/test/resources/pyyaml/colon-in-flow-context.loader-error new file mode 100644 index 00000000..13d50875 --- /dev/null +++ b/src/test/resources/pyyaml/colon-in-flow-context.loader-error @@ -0,0 +1 @@ +{ foo:bar } diff --git a/src/test/resources/pyyaml/construct-binary.data b/src/test/resources/pyyaml/construct-binary.data new file mode 100644 index 00000000..dcdb16f3 --- /dev/null +++ b/src/test/resources/pyyaml/construct-binary.data @@ -0,0 +1,12 @@ +canonical: !!binary "\ + R0lGODlhDAAMAIQAAP//9/X17unp5WZmZgAAAOfn515eXvPz7Y6OjuDg4J+fn5\ + OTk6enp56enmlpaWNjY6Ojo4SEhP/++f/++f/++f/++f/++f/++f/++f/++f/+\ + +f/++f/++f/++f/++f/++SH+Dk1hZGUgd2l0aCBHSU1QACwAAAAADAAMAAAFLC\ + AgjoEwnuNAFOhpEMTRiggcz4BNJHrv/zCFcLiwMWYNG84BwwEeECcgggoBADs=" +generic: !!binary | + R0lGODlhDAAMAIQAAP//9/X17unp5WZmZgAAAOfn515eXvPz7Y6OjuDg4J+fn5 + OTk6enp56enmlpaWNjY6Ojo4SEhP/++f/++f/++f/++f/++f/++f/++f/++f/+ + +f/++f/++f/++f/++f/++SH+Dk1hZGUgd2l0aCBHSU1QACwAAAAADAAMAAAFLC + AgjoEwnuNAFOhpEMTRiggcz4BNJHrv/zCFcLiwMWYNG84BwwEeECcgggoBADs= +description: + The binary value above is a tiny arrow encoded as a gif image. diff --git a/src/test/resources/pyyaml/construct-bool.data b/src/test/resources/pyyaml/construct-bool.data new file mode 100644 index 00000000..36d6519b --- /dev/null +++ b/src/test/resources/pyyaml/construct-bool.data @@ -0,0 +1,9 @@ +canonical: yes +answer: NO +logical: True +option: on + + +but: + y: is a string + n: is a string diff --git a/src/test/resources/pyyaml/construct-custom.data b/src/test/resources/pyyaml/construct-custom.data new file mode 100644 index 00000000..9db0f644 --- /dev/null +++ b/src/test/resources/pyyaml/construct-custom.data @@ -0,0 +1,26 @@ +--- +- !tag1 + x: 1 +- !tag1 + x: 1 + 'y': 2 + z: 3 +- !tag2 + 10 +- !tag2 + =: 10 + 'y': 20 + z: 30 +- !tag3 + x: 1 +- !tag3 + x: 1 + 'y': 2 + z: 3 +- !tag3 + =: 1 + 'y': 2 + z: 3 +- !foo + my-parameter: foo + my-another-parameter: [1,2,3] diff --git a/src/test/resources/pyyaml/construct-float.data b/src/test/resources/pyyaml/construct-float.data new file mode 100644 index 00000000..b662c623 --- /dev/null +++ b/src/test/resources/pyyaml/construct-float.data @@ -0,0 +1,6 @@ +canonical: 6.8523015e+5 +exponential: 685.230_15e+03 +fixed: 685_230.15 +sexagesimal: 190:20:30.15 +negative infinity: -.inf +not a number: .NaN diff --git a/src/test/resources/pyyaml/construct-int.data b/src/test/resources/pyyaml/construct-int.data new file mode 100644 index 00000000..852c3148 --- /dev/null +++ b/src/test/resources/pyyaml/construct-int.data @@ -0,0 +1,6 @@ +canonical: 685230 +decimal: +685_230 +octal: 02472256 +hexadecimal: 0x_0A_74_AE +binary: 0b1010_0111_0100_1010_1110 +sexagesimal: 190:20:30 diff --git a/src/test/resources/pyyaml/construct-map.data b/src/test/resources/pyyaml/construct-map.data new file mode 100644 index 00000000..022446df --- /dev/null +++ b/src/test/resources/pyyaml/construct-map.data @@ -0,0 +1,6 @@ +# Unordered set of key: value pairs. +Block style: !!map + Clark : Evans + Brian : Ingerson + Oren : Ben-Kiki +Flow style: !!map { Clark: Evans, Brian: Ingerson, Oren: Ben-Kiki } diff --git a/src/test/resources/pyyaml/construct-merge.data b/src/test/resources/pyyaml/construct-merge.data new file mode 100644 index 00000000..3fdb2e20 --- /dev/null +++ b/src/test/resources/pyyaml/construct-merge.data @@ -0,0 +1,27 @@ +--- +- &CENTER { x: 1, 'y': 2 } +- &LEFT { x: 0, 'y': 2 } +- &BIG { r: 10 } +- &SMALL { r: 1 } + +# All the following maps are equal: + +- # Explicit keys + x: 1 + 'y': 2 + r: 10 + label: center/big + +- # Merge one map + << : *CENTER + r: 10 + label: center/big + +- # Merge multiple maps + << : [ *CENTER, *BIG ] + label: center/big + +- # Override + << : [ *BIG, *LEFT, *SMALL ] + x: 1 + label: center/big diff --git a/src/test/resources/pyyaml/construct-null.data b/src/test/resources/pyyaml/construct-null.data new file mode 100644 index 00000000..9ad0344c --- /dev/null +++ b/src/test/resources/pyyaml/construct-null.data @@ -0,0 +1,18 @@ +# A document may be null. +--- +--- +# This mapping has four keys, +# one has a value. +empty: +canonical: ~ +english: null +~: null key +--- +# This sequence has five +# entries, two have values. +sparse: + - ~ + - 2nd entry + - + - 4th entry + - Null diff --git a/src/test/resources/pyyaml/construct-omap.data b/src/test/resources/pyyaml/construct-omap.data new file mode 100644 index 00000000..4fa0f45f --- /dev/null +++ b/src/test/resources/pyyaml/construct-omap.data @@ -0,0 +1,8 @@ +# Explicitly typed ordered map (dictionary). +Bestiary: !!omap + - aardvark: African pig-like ant eater. Ugly. + - anteater: South-American ant eater. Two species. + - anaconda: South-American constrictor snake. Scaly. + # Etc. +# Flow style +Numbers: !!omap [ one: 1, two: 2, three : 3 ] diff --git a/src/test/resources/pyyaml/construct-pairs.data b/src/test/resources/pyyaml/construct-pairs.data new file mode 100644 index 00000000..05f55b94 --- /dev/null +++ b/src/test/resources/pyyaml/construct-pairs.data @@ -0,0 +1,7 @@ +# Explicitly typed pairs. +Block tasks: !!pairs + - meeting: with team. + - meeting: with boss. + - break: lunch. + - meeting: with client. +Flow tasks: !!pairs [ meeting: with team, meeting: with boss ] diff --git a/src/test/resources/pyyaml/construct-seq.data b/src/test/resources/pyyaml/construct-seq.data new file mode 100644 index 00000000..bb92fd11 --- /dev/null +++ b/src/test/resources/pyyaml/construct-seq.data @@ -0,0 +1,15 @@ +# Ordered sequence of nodes +Block style: !!seq +- Mercury # Rotates - no light/dark sides. +- Venus # Deadliest. Aptly named. +- Earth # Mostly dirt. +- Mars # Seems empty. +- Jupiter # The king. +- Saturn # Pretty. +- Uranus # Where the sun hardly shines. +- Neptune # Boring. No rings. +- Pluto # You call this a planet? +Flow style: !!seq [ Mercury, Venus, Earth, Mars, # Rocks + Jupiter, Saturn, Uranus, Neptune, # Gas + Pluto ] # Overrated + diff --git a/src/test/resources/pyyaml/construct-set.data b/src/test/resources/pyyaml/construct-set.data new file mode 100644 index 00000000..e05dc885 --- /dev/null +++ b/src/test/resources/pyyaml/construct-set.data @@ -0,0 +1,7 @@ +# Explicitly typed set. +baseball players: !!set + ? Mark McGwire + ? Sammy Sosa + ? Ken Griffey +# Flow style +baseball teams: !!set { Boston Red Sox, Detroit Tigers, New York Yankees } diff --git a/src/test/resources/pyyaml/construct-str-ascii.data b/src/test/resources/pyyaml/construct-str-ascii.data new file mode 100644 index 00000000..0d93013b --- /dev/null +++ b/src/test/resources/pyyaml/construct-str-ascii.data @@ -0,0 +1 @@ +--- !!str "ascii string" diff --git a/src/test/resources/pyyaml/construct-str-utf8.data b/src/test/resources/pyyaml/construct-str-utf8.data new file mode 100644 index 00000000..e355f184 --- /dev/null +++ b/src/test/resources/pyyaml/construct-str-utf8.data @@ -0,0 +1 @@ +--- !!str "Это уникодная строка" diff --git a/src/test/resources/pyyaml/construct-str.data b/src/test/resources/pyyaml/construct-str.data new file mode 100644 index 00000000..606ac6b2 --- /dev/null +++ b/src/test/resources/pyyaml/construct-str.data @@ -0,0 +1 @@ +string: abcd diff --git a/src/test/resources/pyyaml/construct-timestamp.data b/src/test/resources/pyyaml/construct-timestamp.data new file mode 100644 index 00000000..c5f3840b --- /dev/null +++ b/src/test/resources/pyyaml/construct-timestamp.data @@ -0,0 +1,5 @@ +canonical: 2001-12-15T02:59:43.1Z +valid iso8601: 2001-12-14t21:59:43.10-05:00 +space separated: 2001-12-14 21:59:43.10 -5 +no time zone (Z): 2001-12-15 2:59:43.10 +date (00:00:00Z): 2002-12-14 diff --git a/src/test/resources/pyyaml/construct-value.data b/src/test/resources/pyyaml/construct-value.data new file mode 100644 index 00000000..3eb79198 --- /dev/null +++ b/src/test/resources/pyyaml/construct-value.data @@ -0,0 +1,10 @@ +--- # Old schema +link with: + - library1.dll + - library2.dll +--- # New schema +link with: + - = : library1.dll + version: 1.2 + - = : library2.dll + version: 2.3 diff --git a/src/test/resources/pyyaml/document-separator-in-quoted-scalar.loader-error b/src/test/resources/pyyaml/document-separator-in-quoted-scalar.loader-error new file mode 100644 index 00000000..9eeb0d6f --- /dev/null +++ b/src/test/resources/pyyaml/document-separator-in-quoted-scalar.loader-error @@ -0,0 +1,11 @@ +--- +"this --- is correct" +--- +"this +...is also +correct" +--- +"a quoted scalar +cannot contain +--- +document separators" diff --git a/src/test/resources/pyyaml/documents.events b/src/test/resources/pyyaml/documents.events new file mode 100644 index 00000000..775a51a7 --- /dev/null +++ b/src/test/resources/pyyaml/documents.events @@ -0,0 +1,11 @@ +- !StreamStart +- !DocumentStart { explicit: false } +- !Scalar { implicit: [true,false], value: 'data' } +- !DocumentEnd +- !DocumentStart +- !Scalar { implicit: [true,false] } +- !DocumentEnd +- !DocumentStart { version: [1,1], tags: { '!': '!foo', '!yaml!': 'tag:yaml.org,2002:', '!ugly!': '!!!!!!!' } } +- !Scalar { implicit: [true,false] } +- !DocumentEnd +- !StreamEnd diff --git a/src/test/resources/pyyaml/duplicate-anchor-1.loader-error b/src/test/resources/pyyaml/duplicate-anchor-1.loader-error new file mode 100644 index 00000000..906cf29d --- /dev/null +++ b/src/test/resources/pyyaml/duplicate-anchor-1.loader-error @@ -0,0 +1,3 @@ +- &foo bar +- &bar bar +- &foo bar diff --git a/src/test/resources/pyyaml/duplicate-anchor-2.loader-error b/src/test/resources/pyyaml/duplicate-anchor-2.loader-error new file mode 100644 index 00000000..62b43897 --- /dev/null +++ b/src/test/resources/pyyaml/duplicate-anchor-2.loader-error @@ -0,0 +1 @@ +&foo [1, 2, 3, &foo 4] diff --git a/src/test/resources/pyyaml/duplicate-key.former-loader-error.data b/src/test/resources/pyyaml/duplicate-key.former-loader-error.data new file mode 100644 index 00000000..84deb8f2 --- /dev/null +++ b/src/test/resources/pyyaml/duplicate-key.former-loader-error.data @@ -0,0 +1,3 @@ +--- +foo: bar +foo: baz diff --git a/src/test/resources/pyyaml/duplicate-mapping-key.former-loader-error.data b/src/test/resources/pyyaml/duplicate-mapping-key.former-loader-error.data new file mode 100644 index 00000000..7e7b4d13 --- /dev/null +++ b/src/test/resources/pyyaml/duplicate-mapping-key.former-loader-error.data @@ -0,0 +1,6 @@ +--- +&anchor foo: + foo: bar + *anchor: duplicate key + baz: bat + *anchor: duplicate key diff --git a/src/test/resources/pyyaml/duplicate-merge-key.former-loader-error.data b/src/test/resources/pyyaml/duplicate-merge-key.former-loader-error.data new file mode 100644 index 00000000..cebc3a18 --- /dev/null +++ b/src/test/resources/pyyaml/duplicate-merge-key.former-loader-error.data @@ -0,0 +1,4 @@ +--- +<<: {x: 1, y: 2} +foo: bar +<<: {z: 3, t: 4} diff --git a/src/test/resources/pyyaml/duplicate-tag-directive.loader-error b/src/test/resources/pyyaml/duplicate-tag-directive.loader-error new file mode 100644 index 00000000..50c81a06 --- /dev/null +++ b/src/test/resources/pyyaml/duplicate-tag-directive.loader-error @@ -0,0 +1,3 @@ +%TAG !foo! bar +%TAG !foo! baz +--- foo diff --git a/src/test/resources/pyyaml/duplicate-value-key.former-loader-error.data b/src/test/resources/pyyaml/duplicate-value-key.former-loader-error.data new file mode 100644 index 00000000..b34a1d69 --- /dev/null +++ b/src/test/resources/pyyaml/duplicate-value-key.former-loader-error.data @@ -0,0 +1,4 @@ +--- +=: 1 +foo: bar +=: 2 diff --git a/src/test/resources/pyyaml/duplicate-yaml-directive.loader-error b/src/test/resources/pyyaml/duplicate-yaml-directive.loader-error new file mode 100644 index 00000000..9b723905 --- /dev/null +++ b/src/test/resources/pyyaml/duplicate-yaml-directive.loader-error @@ -0,0 +1,3 @@ +%YAML 1.1 +%YAML 1.1 +--- foo diff --git a/src/test/resources/pyyaml/emit-block-scalar-in-simple-key-context-bug.canonical b/src/test/resources/pyyaml/emit-block-scalar-in-simple-key-context-bug.canonical new file mode 100644 index 00000000..473bed5d --- /dev/null +++ b/src/test/resources/pyyaml/emit-block-scalar-in-simple-key-context-bug.canonical @@ -0,0 +1,6 @@ +%YAML 1.1 +--- !!map +{ + ? !!str "foo" + : !!str "bar" +} diff --git a/src/test/resources/pyyaml/emit-block-scalar-in-simple-key-context-bug.data b/src/test/resources/pyyaml/emit-block-scalar-in-simple-key-context-bug.data new file mode 100644 index 00000000..b6b42ba5 --- /dev/null +++ b/src/test/resources/pyyaml/emit-block-scalar-in-simple-key-context-bug.data @@ -0,0 +1,4 @@ +? |- + foo +: |- + bar diff --git a/src/test/resources/pyyaml/emitting-unacceptable-unicode-character-bug.data b/src/test/resources/pyyaml/emitting-unacceptable-unicode-character-bug.data new file mode 100644 index 00000000..2a5df00d --- /dev/null +++ b/src/test/resources/pyyaml/emitting-unacceptable-unicode-character-bug.data @@ -0,0 +1 @@ +"\udd00" diff --git a/src/test/resources/pyyaml/empty-anchor.emitter-error b/src/test/resources/pyyaml/empty-anchor.emitter-error new file mode 100644 index 00000000..ce663b63 --- /dev/null +++ b/src/test/resources/pyyaml/empty-anchor.emitter-error @@ -0,0 +1,5 @@ +- !StreamStart +- !DocumentStart +- !Scalar { anchor: '', value: 'foo' } +- !DocumentEnd +- !StreamEnd diff --git a/src/test/resources/pyyaml/empty-document-bug.canonical b/src/test/resources/pyyaml/empty-document-bug.canonical new file mode 100644 index 00000000..28a6cf13 --- /dev/null +++ b/src/test/resources/pyyaml/empty-document-bug.canonical @@ -0,0 +1 @@ +# This YAML stream contains no YAML documents. diff --git a/src/test/resources/pyyaml/empty-document-bug.data b/src/test/resources/pyyaml/empty-document-bug.data new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/src/test/resources/pyyaml/empty-document-bug.data diff --git a/src/test/resources/pyyaml/empty-documents.single-loader-error b/src/test/resources/pyyaml/empty-documents.single-loader-error new file mode 100644 index 00000000..f8dba8d4 --- /dev/null +++ b/src/test/resources/pyyaml/empty-documents.single-loader-error @@ -0,0 +1,2 @@ +--- # first document +--- # second document diff --git a/src/test/resources/pyyaml/empty-tag-handle.emitter-error b/src/test/resources/pyyaml/empty-tag-handle.emitter-error new file mode 100644 index 00000000..235c8998 --- /dev/null +++ b/src/test/resources/pyyaml/empty-tag-handle.emitter-error @@ -0,0 +1,5 @@ +- !StreamStart +- !DocumentStart { tags: { '': 'bar' } } +- !Scalar { value: 'foo' } +- !DocumentEnd +- !StreamEnd diff --git a/src/test/resources/pyyaml/empty-tag-prefix.emitter-error b/src/test/resources/pyyaml/empty-tag-prefix.emitter-error new file mode 100644 index 00000000..c6c0e955 --- /dev/null +++ b/src/test/resources/pyyaml/empty-tag-prefix.emitter-error @@ -0,0 +1,5 @@ +- !StreamStart +- !DocumentStart { tags: { '!': '' } } +- !Scalar { value: 'foo' } +- !DocumentEnd +- !StreamEnd diff --git a/src/test/resources/pyyaml/empty-tag.emitter-error b/src/test/resources/pyyaml/empty-tag.emitter-error new file mode 100644 index 00000000..b7ca5931 --- /dev/null +++ b/src/test/resources/pyyaml/empty-tag.emitter-error @@ -0,0 +1,5 @@ +- !StreamStart +- !DocumentStart +- !Scalar { tag: '', value: 'key', implicit: [false,false] } +- !DocumentEnd +- !StreamEnd diff --git a/src/test/resources/pyyaml/expected-document-end.emitter-error b/src/test/resources/pyyaml/expected-document-end.emitter-error new file mode 100644 index 00000000..0cbab899 --- /dev/null +++ b/src/test/resources/pyyaml/expected-document-end.emitter-error @@ -0,0 +1,6 @@ +- !StreamStart +- !DocumentStart +- !Scalar { value: 'data 1' } +- !Scalar { value: 'data 2' } +- !DocumentEnd +- !StreamEnd diff --git a/src/test/resources/pyyaml/expected-document-start.emitter-error b/src/test/resources/pyyaml/expected-document-start.emitter-error new file mode 100644 index 00000000..8ce575ec --- /dev/null +++ b/src/test/resources/pyyaml/expected-document-start.emitter-error @@ -0,0 +1,4 @@ +- !StreamStart +- !MappingStart +- !MappingEnd +- !StreamEnd diff --git a/src/test/resources/pyyaml/expected-mapping.loader-error b/src/test/resources/pyyaml/expected-mapping.loader-error new file mode 100644 index 00000000..82aed98a --- /dev/null +++ b/src/test/resources/pyyaml/expected-mapping.loader-error @@ -0,0 +1 @@ +--- !!map [not, a, map] diff --git a/src/test/resources/pyyaml/expected-node-1.emitter-error b/src/test/resources/pyyaml/expected-node-1.emitter-error new file mode 100644 index 00000000..36ceca3e --- /dev/null +++ b/src/test/resources/pyyaml/expected-node-1.emitter-error @@ -0,0 +1,4 @@ +- !StreamStart +- !DocumentStart +- !DocumentEnd +- !StreamEnd diff --git a/src/test/resources/pyyaml/expected-node-2.emitter-error b/src/test/resources/pyyaml/expected-node-2.emitter-error new file mode 100644 index 00000000..891ee370 --- /dev/null +++ b/src/test/resources/pyyaml/expected-node-2.emitter-error @@ -0,0 +1,7 @@ +- !StreamStart +- !DocumentStart +- !MappingStart +- !Scalar { value: 'key' } +- !MappingEnd +- !DocumentEnd +- !StreamEnd diff --git a/src/test/resources/pyyaml/expected-nothing.emitter-error b/src/test/resources/pyyaml/expected-nothing.emitter-error new file mode 100644 index 00000000..62c54d3e --- /dev/null +++ b/src/test/resources/pyyaml/expected-nothing.emitter-error @@ -0,0 +1,4 @@ +- !StreamStart +- !StreamEnd +- !StreamStart +- !StreamEnd diff --git a/src/test/resources/pyyaml/expected-scalar.loader-error b/src/test/resources/pyyaml/expected-scalar.loader-error new file mode 100644 index 00000000..7b3171e8 --- /dev/null +++ b/src/test/resources/pyyaml/expected-scalar.loader-error @@ -0,0 +1 @@ +--- !!str [not a scalar] diff --git a/src/test/resources/pyyaml/expected-sequence.loader-error b/src/test/resources/pyyaml/expected-sequence.loader-error new file mode 100644 index 00000000..08074ea5 --- /dev/null +++ b/src/test/resources/pyyaml/expected-sequence.loader-error @@ -0,0 +1 @@ +--- !!seq {foo, bar, baz} diff --git a/src/test/resources/pyyaml/expected-stream-start.emitter-error b/src/test/resources/pyyaml/expected-stream-start.emitter-error new file mode 100644 index 00000000..480dc2eb --- /dev/null +++ b/src/test/resources/pyyaml/expected-stream-start.emitter-error @@ -0,0 +1,2 @@ +- !DocumentStart +- !DocumentEnd diff --git a/src/test/resources/pyyaml/explicit-document.single-loader-error b/src/test/resources/pyyaml/explicit-document.single-loader-error new file mode 100644 index 00000000..46c6f8b7 --- /dev/null +++ b/src/test/resources/pyyaml/explicit-document.single-loader-error @@ -0,0 +1,4 @@ +--- +foo: bar +--- +foo: bar diff --git a/src/test/resources/pyyaml/fetch-complex-value-bug.loader-error b/src/test/resources/pyyaml/fetch-complex-value-bug.loader-error new file mode 100644 index 00000000..25fac24e --- /dev/null +++ b/src/test/resources/pyyaml/fetch-complex-value-bug.loader-error @@ -0,0 +1,2 @@ +? "foo" + : "bar" diff --git a/src/test/resources/pyyaml/float-representer-2.3-bug.data b/src/test/resources/pyyaml/float-representer-2.3-bug.data new file mode 100644 index 00000000..efd17163 --- /dev/null +++ b/src/test/resources/pyyaml/float-representer-2.3-bug.data @@ -0,0 +1,5 @@ +#0.0: # hash(0) == hash(nan) and 0 == nan in Python 2.3 +1.0: 1 ++.inf: 10 +-.inf: -10 +.nan: 100 diff --git a/src/test/resources/pyyaml/float.data b/src/test/resources/pyyaml/float.data new file mode 100644 index 00000000..524d5db3 --- /dev/null +++ b/src/test/resources/pyyaml/float.data @@ -0,0 +1,6 @@ +- 6.8523015e+5 +- 685.230_15e+03 +- 685_230.15 +- 190:20:30.15 +- -.inf +- .NaN diff --git a/src/test/resources/pyyaml/forbidden-entry.loader-error b/src/test/resources/pyyaml/forbidden-entry.loader-error new file mode 100644 index 00000000..f2e30796 --- /dev/null +++ b/src/test/resources/pyyaml/forbidden-entry.loader-error @@ -0,0 +1,2 @@ +test: - foo + - bar diff --git a/src/test/resources/pyyaml/forbidden-key.loader-error b/src/test/resources/pyyaml/forbidden-key.loader-error new file mode 100644 index 00000000..da9b471d --- /dev/null +++ b/src/test/resources/pyyaml/forbidden-key.loader-error @@ -0,0 +1,2 @@ +test: ? foo + : bar diff --git a/src/test/resources/pyyaml/forbidden-value.loader-error b/src/test/resources/pyyaml/forbidden-value.loader-error new file mode 100644 index 00000000..efd7ce58 --- /dev/null +++ b/src/test/resources/pyyaml/forbidden-value.loader-error @@ -0,0 +1 @@ +test: key: value diff --git a/src/test/resources/pyyaml/implicit-document.single-loader-error b/src/test/resources/pyyaml/implicit-document.single-loader-error new file mode 100644 index 00000000..f8c9a5c6 --- /dev/null +++ b/src/test/resources/pyyaml/implicit-document.single-loader-error @@ -0,0 +1,3 @@ +foo: bar +--- +foo: bar diff --git a/src/test/resources/pyyaml/int.data b/src/test/resources/pyyaml/int.data new file mode 100644 index 00000000..d44d3761 --- /dev/null +++ b/src/test/resources/pyyaml/int.data @@ -0,0 +1,6 @@ +- 685230 +- +685_230 +- 02472256 +- 0x_0A_74_AE +- 0b1010_0111_0100_1010_1110 +- 190:20:30 diff --git a/src/test/resources/pyyaml/invalid-anchor-1.loader-error b/src/test/resources/pyyaml/invalid-anchor-1.loader-error new file mode 100644 index 00000000..fcf7d0f6 --- /dev/null +++ b/src/test/resources/pyyaml/invalid-anchor-1.loader-error @@ -0,0 +1 @@ +--- &? foo # we allow only ascii and numeric characters in anchor names. diff --git a/src/test/resources/pyyaml/invalid-anchor-2.loader-error b/src/test/resources/pyyaml/invalid-anchor-2.loader-error new file mode 100644 index 00000000..bfc4ff01 --- /dev/null +++ b/src/test/resources/pyyaml/invalid-anchor-2.loader-error @@ -0,0 +1,8 @@ +--- +- [ + &correct foo, + *correct, + *correct] # still correct +- *correct: still correct +- &correct-or-not[foo, bar] + diff --git a/src/test/resources/pyyaml/invalid-anchor.emitter-error b/src/test/resources/pyyaml/invalid-anchor.emitter-error new file mode 100644 index 00000000..3d2a8148 --- /dev/null +++ b/src/test/resources/pyyaml/invalid-anchor.emitter-error @@ -0,0 +1,5 @@ +- !StreamStart +- !DocumentStart +- !Scalar { anchor: '5*5=25', value: 'foo' } +- !DocumentEnd +- !StreamEnd diff --git a/src/test/resources/pyyaml/invalid-base64-data.loader-error b/src/test/resources/pyyaml/invalid-base64-data.loader-error new file mode 100644 index 00000000..798abbae --- /dev/null +++ b/src/test/resources/pyyaml/invalid-base64-data.loader-error @@ -0,0 +1,2 @@ +--- !!binary + binary data encoded in base64 should be here. diff --git a/src/test/resources/pyyaml/invalid-block-scalar-indicator.loader-error b/src/test/resources/pyyaml/invalid-block-scalar-indicator.loader-error new file mode 100644 index 00000000..16a6db18 --- /dev/null +++ b/src/test/resources/pyyaml/invalid-block-scalar-indicator.loader-error @@ -0,0 +1,2 @@ +--- > what is this? # a comment +data diff --git a/src/test/resources/pyyaml/invalid-character.loader-error b/src/test/resources/pyyaml/invalid-character.loader-error Binary files differnew file mode 100644 index 00000000..03687b02 --- /dev/null +++ b/src/test/resources/pyyaml/invalid-character.loader-error diff --git a/src/test/resources/pyyaml/invalid-character.stream-error b/src/test/resources/pyyaml/invalid-character.stream-error Binary files differnew file mode 100644 index 00000000..03687b02 --- /dev/null +++ b/src/test/resources/pyyaml/invalid-character.stream-error diff --git a/src/test/resources/pyyaml/invalid-directive-line.loader-error b/src/test/resources/pyyaml/invalid-directive-line.loader-error new file mode 100644 index 00000000..0892eb66 --- /dev/null +++ b/src/test/resources/pyyaml/invalid-directive-line.loader-error @@ -0,0 +1,2 @@ +%YAML 1.1 ? # extra symbol +--- diff --git a/src/test/resources/pyyaml/invalid-directive-name-1.loader-error b/src/test/resources/pyyaml/invalid-directive-name-1.loader-error new file mode 100644 index 00000000..153fd889 --- /dev/null +++ b/src/test/resources/pyyaml/invalid-directive-name-1.loader-error @@ -0,0 +1,2 @@ +% # no name at all +--- diff --git a/src/test/resources/pyyaml/invalid-directive-name-2.loader-error b/src/test/resources/pyyaml/invalid-directive-name-2.loader-error new file mode 100644 index 00000000..3732a06a --- /dev/null +++ b/src/test/resources/pyyaml/invalid-directive-name-2.loader-error @@ -0,0 +1,2 @@ +%invalid-characters:in-directive name +--- diff --git a/src/test/resources/pyyaml/invalid-escape-character.loader-error b/src/test/resources/pyyaml/invalid-escape-character.loader-error new file mode 100644 index 00000000..a95ab767 --- /dev/null +++ b/src/test/resources/pyyaml/invalid-escape-character.loader-error @@ -0,0 +1 @@ +"some escape characters are \ncorrect, but this one \?\nis not\n" diff --git a/src/test/resources/pyyaml/invalid-escape-numbers.loader-error b/src/test/resources/pyyaml/invalid-escape-numbers.loader-error new file mode 100644 index 00000000..614ec9f5 --- /dev/null +++ b/src/test/resources/pyyaml/invalid-escape-numbers.loader-error @@ -0,0 +1 @@ +"hm.... \u123?" diff --git a/src/test/resources/pyyaml/invalid-indentation-indicator-1.loader-error b/src/test/resources/pyyaml/invalid-indentation-indicator-1.loader-error new file mode 100644 index 00000000..a3cd12f5 --- /dev/null +++ b/src/test/resources/pyyaml/invalid-indentation-indicator-1.loader-error @@ -0,0 +1,2 @@ +--- >0 # not valid +data diff --git a/src/test/resources/pyyaml/invalid-indentation-indicator-2.loader-error b/src/test/resources/pyyaml/invalid-indentation-indicator-2.loader-error new file mode 100644 index 00000000..eefb6ecd --- /dev/null +++ b/src/test/resources/pyyaml/invalid-indentation-indicator-2.loader-error @@ -0,0 +1,2 @@ +--- >-0 +data diff --git a/src/test/resources/pyyaml/invalid-merge-1.loader-error b/src/test/resources/pyyaml/invalid-merge-1.loader-error new file mode 100644 index 00000000..fc3c2844 --- /dev/null +++ b/src/test/resources/pyyaml/invalid-merge-1.loader-error @@ -0,0 +1,2 @@ +foo: bar +<<: baz diff --git a/src/test/resources/pyyaml/invalid-merge-2.loader-error b/src/test/resources/pyyaml/invalid-merge-2.loader-error new file mode 100644 index 00000000..8e88615c --- /dev/null +++ b/src/test/resources/pyyaml/invalid-merge-2.loader-error @@ -0,0 +1,2 @@ +foo: bar +<<: [x: 1, y: 2, z, t: 4] diff --git a/src/test/resources/pyyaml/invalid-omap-1.loader-error b/src/test/resources/pyyaml/invalid-omap-1.loader-error new file mode 100644 index 00000000..28633926 --- /dev/null +++ b/src/test/resources/pyyaml/invalid-omap-1.loader-error @@ -0,0 +1,3 @@ +--- !!omap +foo: bar +baz: bat diff --git a/src/test/resources/pyyaml/invalid-omap-2.loader-error b/src/test/resources/pyyaml/invalid-omap-2.loader-error new file mode 100644 index 00000000..c377dfb8 --- /dev/null +++ b/src/test/resources/pyyaml/invalid-omap-2.loader-error @@ -0,0 +1,3 @@ +--- !!omap +- foo: bar +- baz diff --git a/src/test/resources/pyyaml/invalid-omap-3.loader-error b/src/test/resources/pyyaml/invalid-omap-3.loader-error new file mode 100644 index 00000000..2a4f50d9 --- /dev/null +++ b/src/test/resources/pyyaml/invalid-omap-3.loader-error @@ -0,0 +1,4 @@ +--- !!omap +- foo: bar +- baz: bar + bar: bar diff --git a/src/test/resources/pyyaml/invalid-pairs-1.loader-error b/src/test/resources/pyyaml/invalid-pairs-1.loader-error new file mode 100644 index 00000000..42d19aec --- /dev/null +++ b/src/test/resources/pyyaml/invalid-pairs-1.loader-error @@ -0,0 +1,3 @@ +--- !!pairs +foo: bar +baz: bat diff --git a/src/test/resources/pyyaml/invalid-pairs-2.loader-error b/src/test/resources/pyyaml/invalid-pairs-2.loader-error new file mode 100644 index 00000000..31389eae --- /dev/null +++ b/src/test/resources/pyyaml/invalid-pairs-2.loader-error @@ -0,0 +1,3 @@ +--- !!pairs +- foo: bar +- baz diff --git a/src/test/resources/pyyaml/invalid-pairs-3.loader-error b/src/test/resources/pyyaml/invalid-pairs-3.loader-error new file mode 100644 index 00000000..f8d7704e --- /dev/null +++ b/src/test/resources/pyyaml/invalid-pairs-3.loader-error @@ -0,0 +1,4 @@ +--- !!pairs +- foo: bar +- baz: bar + bar: bar diff --git a/src/test/resources/pyyaml/invalid-simple-key.loader-error b/src/test/resources/pyyaml/invalid-simple-key.loader-error new file mode 100644 index 00000000..a58deecf --- /dev/null +++ b/src/test/resources/pyyaml/invalid-simple-key.loader-error @@ -0,0 +1,3 @@ +key: value +invalid simple key +next key: next value diff --git a/src/test/resources/pyyaml/invalid-single-quote-bug.data b/src/test/resources/pyyaml/invalid-single-quote-bug.data new file mode 100644 index 00000000..76ef7ae3 --- /dev/null +++ b/src/test/resources/pyyaml/invalid-single-quote-bug.data @@ -0,0 +1,2 @@ +- "foo 'bar'" +- "foo\n'bar'" diff --git a/src/test/resources/pyyaml/invalid-starting-character.loader-error b/src/test/resources/pyyaml/invalid-starting-character.loader-error new file mode 100644 index 00000000..bb81c60c --- /dev/null +++ b/src/test/resources/pyyaml/invalid-starting-character.loader-error @@ -0,0 +1 @@ +@@@@@@@@@@@@@@@@@@@ diff --git a/src/test/resources/pyyaml/invalid-tag-1.loader-error b/src/test/resources/pyyaml/invalid-tag-1.loader-error new file mode 100644 index 00000000..a68cd384 --- /dev/null +++ b/src/test/resources/pyyaml/invalid-tag-1.loader-error @@ -0,0 +1 @@ +- !<foo#bar> baz diff --git a/src/test/resources/pyyaml/invalid-tag-2.loader-error b/src/test/resources/pyyaml/invalid-tag-2.loader-error new file mode 100644 index 00000000..3a36700a --- /dev/null +++ b/src/test/resources/pyyaml/invalid-tag-2.loader-error @@ -0,0 +1 @@ +- !prefix!foo#bar baz diff --git a/src/test/resources/pyyaml/invalid-tag-directive-handle.loader-error b/src/test/resources/pyyaml/invalid-tag-directive-handle.loader-error new file mode 100644 index 00000000..42b5d7e9 --- /dev/null +++ b/src/test/resources/pyyaml/invalid-tag-directive-handle.loader-error @@ -0,0 +1,2 @@ +%TAG !!! !!! +--- diff --git a/src/test/resources/pyyaml/invalid-tag-directive-prefix.loader-error b/src/test/resources/pyyaml/invalid-tag-directive-prefix.loader-error new file mode 100644 index 00000000..0cb482c9 --- /dev/null +++ b/src/test/resources/pyyaml/invalid-tag-directive-prefix.loader-error @@ -0,0 +1,2 @@ +%TAG ! tag:zz.com/foo#bar # '#' is not allowed in URLs +--- diff --git a/src/test/resources/pyyaml/invalid-tag-handle-1.emitter-error b/src/test/resources/pyyaml/invalid-tag-handle-1.emitter-error new file mode 100644 index 00000000..d5df9a26 --- /dev/null +++ b/src/test/resources/pyyaml/invalid-tag-handle-1.emitter-error @@ -0,0 +1,5 @@ +- !StreamStart +- !DocumentStart { tags: { '!foo': 'bar' } } +- !Scalar { value: 'foo' } +- !DocumentEnd +- !StreamEnd diff --git a/src/test/resources/pyyaml/invalid-tag-handle-1.loader-error b/src/test/resources/pyyaml/invalid-tag-handle-1.loader-error new file mode 100644 index 00000000..ef0d1430 --- /dev/null +++ b/src/test/resources/pyyaml/invalid-tag-handle-1.loader-error @@ -0,0 +1,2 @@ +%TAG foo bar +--- diff --git a/src/test/resources/pyyaml/invalid-tag-handle-2.emitter-error b/src/test/resources/pyyaml/invalid-tag-handle-2.emitter-error new file mode 100644 index 00000000..d1831d55 --- /dev/null +++ b/src/test/resources/pyyaml/invalid-tag-handle-2.emitter-error @@ -0,0 +1,5 @@ +- !StreamStart +- !DocumentStart { tags: { '!!!': 'bar' } } +- !Scalar { value: 'foo' } +- !DocumentEnd +- !StreamEnd diff --git a/src/test/resources/pyyaml/invalid-tag-handle-2.loader-error b/src/test/resources/pyyaml/invalid-tag-handle-2.loader-error new file mode 100644 index 00000000..06c7f0e4 --- /dev/null +++ b/src/test/resources/pyyaml/invalid-tag-handle-2.loader-error @@ -0,0 +1,2 @@ +%TAG !foo bar +--- diff --git a/src/test/resources/pyyaml/invalid-uri-escapes-1.loader-error b/src/test/resources/pyyaml/invalid-uri-escapes-1.loader-error new file mode 100644 index 00000000..a6ecb36a --- /dev/null +++ b/src/test/resources/pyyaml/invalid-uri-escapes-1.loader-error @@ -0,0 +1 @@ +--- !<tag:%x?y> foo diff --git a/src/test/resources/pyyaml/invalid-uri-escapes-2.loader-error b/src/test/resources/pyyaml/invalid-uri-escapes-2.loader-error new file mode 100644 index 00000000..b89e8f6a --- /dev/null +++ b/src/test/resources/pyyaml/invalid-uri-escapes-2.loader-error @@ -0,0 +1 @@ +--- !<%FF> foo diff --git a/src/test/resources/pyyaml/invalid-uri-escapes-3.loader-error b/src/test/resources/pyyaml/invalid-uri-escapes-3.loader-error new file mode 100644 index 00000000..f2e4cb82 --- /dev/null +++ b/src/test/resources/pyyaml/invalid-uri-escapes-3.loader-error @@ -0,0 +1 @@ +--- !<foo%d0%af%d0%af%d0bar> baz diff --git a/src/test/resources/pyyaml/invalid-uri.loader-error b/src/test/resources/pyyaml/invalid-uri.loader-error new file mode 100644 index 00000000..06307e06 --- /dev/null +++ b/src/test/resources/pyyaml/invalid-uri.loader-error @@ -0,0 +1 @@ +--- !foo! bar diff --git a/src/test/resources/pyyaml/invalid-utf8-byte.loader-error b/src/test/resources/pyyaml/invalid-utf8-byte.loader-error new file mode 100644 index 00000000..15111c3e --- /dev/null +++ b/src/test/resources/pyyaml/invalid-utf8-byte.loader-error @@ -0,0 +1,18 @@ +------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------- +Invalid byte ('\xFF'): <-- +------------------------------------------------------------------------------------------------------------------------------- diff --git a/src/test/resources/pyyaml/invalid-utf8-byte.stream-error b/src/test/resources/pyyaml/invalid-utf8-byte.stream-error new file mode 100644 index 00000000..15111c3e --- /dev/null +++ b/src/test/resources/pyyaml/invalid-utf8-byte.stream-error @@ -0,0 +1,18 @@ +------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------- +Invalid byte ('\xFF'): <-- +------------------------------------------------------------------------------------------------------------------------------- diff --git a/src/test/resources/pyyaml/invalid-yaml-directive-version-1.loader-error b/src/test/resources/pyyaml/invalid-yaml-directive-version-1.loader-error new file mode 100644 index 00000000..e9b4e3a6 --- /dev/null +++ b/src/test/resources/pyyaml/invalid-yaml-directive-version-1.loader-error @@ -0,0 +1,3 @@ +# No version at all. +%YAML +--- diff --git a/src/test/resources/pyyaml/invalid-yaml-directive-version-2.loader-error b/src/test/resources/pyyaml/invalid-yaml-directive-version-2.loader-error new file mode 100644 index 00000000..6aa7740e --- /dev/null +++ b/src/test/resources/pyyaml/invalid-yaml-directive-version-2.loader-error @@ -0,0 +1,2 @@ +%YAML 1e-5 +--- diff --git a/src/test/resources/pyyaml/invalid-yaml-directive-version-3.loader-error b/src/test/resources/pyyaml/invalid-yaml-directive-version-3.loader-error new file mode 100644 index 00000000..345e7842 --- /dev/null +++ b/src/test/resources/pyyaml/invalid-yaml-directive-version-3.loader-error @@ -0,0 +1,2 @@ +%YAML 1. +--- diff --git a/src/test/resources/pyyaml/invalid-yaml-directive-version-4.loader-error b/src/test/resources/pyyaml/invalid-yaml-directive-version-4.loader-error new file mode 100644 index 00000000..b35ca820 --- /dev/null +++ b/src/test/resources/pyyaml/invalid-yaml-directive-version-4.loader-error @@ -0,0 +1,2 @@ +%YAML 1.132.435 +--- diff --git a/src/test/resources/pyyaml/invalid-yaml-directive-version-5.loader-error b/src/test/resources/pyyaml/invalid-yaml-directive-version-5.loader-error new file mode 100644 index 00000000..7c2b49f5 --- /dev/null +++ b/src/test/resources/pyyaml/invalid-yaml-directive-version-5.loader-error @@ -0,0 +1,2 @@ +%YAML A.0 +--- diff --git a/src/test/resources/pyyaml/invalid-yaml-directive-version-6.loader-error b/src/test/resources/pyyaml/invalid-yaml-directive-version-6.loader-error new file mode 100644 index 00000000..bae714fc --- /dev/null +++ b/src/test/resources/pyyaml/invalid-yaml-directive-version-6.loader-error @@ -0,0 +1,2 @@ +%YAML 123.C +--- diff --git a/src/test/resources/pyyaml/invalid-yaml-version.loader-error b/src/test/resources/pyyaml/invalid-yaml-version.loader-error new file mode 100644 index 00000000..dd019488 --- /dev/null +++ b/src/test/resources/pyyaml/invalid-yaml-version.loader-error @@ -0,0 +1,2 @@ +%YAML 2.0 +--- foo diff --git a/src/test/resources/pyyaml/mappings.events b/src/test/resources/pyyaml/mappings.events new file mode 100644 index 00000000..3cb5579f --- /dev/null +++ b/src/test/resources/pyyaml/mappings.events @@ -0,0 +1,44 @@ +- !StreamStart + +- !DocumentStart +- !MappingStart +- !Scalar { implicit: [true,true], value: 'key' } +- !Scalar { implicit: [true,true], value: 'value' } +- !Scalar { implicit: [true,true], value: 'empty mapping' } +- !MappingStart +- !MappingEnd +- !Scalar { implicit: [true,true], value: 'empty mapping with tag' } +- !MappingStart { tag: '!mytag', implicit: false } +- !MappingEnd +- !Scalar { implicit: [true,true], value: 'block mapping' } +- !MappingStart +- !MappingStart +- !Scalar { implicit: [true,true], value: 'complex' } +- !Scalar { implicit: [true,true], value: 'key' } +- !Scalar { implicit: [true,true], value: 'complex' } +- !Scalar { implicit: [true,true], value: 'key' } +- !MappingEnd +- !MappingStart +- !Scalar { implicit: [true,true], value: 'complex' } +- !Scalar { implicit: [true,true], value: 'key' } +- !MappingEnd +- !MappingEnd +- !Scalar { implicit: [true,true], value: 'flow mapping' } +- !MappingStart { flow_style: true } +- !Scalar { implicit: [true,true], value: 'key' } +- !Scalar { implicit: [true,true], value: 'value' } +- !MappingStart +- !Scalar { implicit: [true,true], value: 'complex' } +- !Scalar { implicit: [true,true], value: 'key' } +- !Scalar { implicit: [true,true], value: 'complex' } +- !Scalar { implicit: [true,true], value: 'key' } +- !MappingEnd +- !MappingStart +- !Scalar { implicit: [true,true], value: 'complex' } +- !Scalar { implicit: [true,true], value: 'key' } +- !MappingEnd +- !MappingEnd +- !MappingEnd +- !DocumentEnd + +- !StreamEnd diff --git a/src/test/resources/pyyaml/merge.data b/src/test/resources/pyyaml/merge.data new file mode 100644 index 00000000..e455bbcd --- /dev/null +++ b/src/test/resources/pyyaml/merge.data @@ -0,0 +1 @@ +- << diff --git a/src/test/resources/pyyaml/more-floats.data b/src/test/resources/pyyaml/more-floats.data new file mode 100644 index 00000000..399eb177 --- /dev/null +++ b/src/test/resources/pyyaml/more-floats.data @@ -0,0 +1 @@ +[0.0, +1.0, -1.0, +.inf, -.inf, .nan, .nan] diff --git a/src/test/resources/pyyaml/negative-float-bug.data b/src/test/resources/pyyaml/negative-float-bug.data new file mode 100644 index 00000000..18e16e38 --- /dev/null +++ b/src/test/resources/pyyaml/negative-float-bug.data @@ -0,0 +1 @@ +-1.0 diff --git a/src/test/resources/pyyaml/no-alias-anchor.emitter-error b/src/test/resources/pyyaml/no-alias-anchor.emitter-error new file mode 100644 index 00000000..5ff065c1 --- /dev/null +++ b/src/test/resources/pyyaml/no-alias-anchor.emitter-error @@ -0,0 +1,8 @@ +- !StreamStart +- !DocumentStart +- !SequenceStart +- !Scalar { anchor: A, value: data } +- !Alias { } +- !SequenceEnd +- !DocumentEnd +- !StreamEnd diff --git a/src/test/resources/pyyaml/no-block-collection-end.loader-error b/src/test/resources/pyyaml/no-block-collection-end.loader-error new file mode 100644 index 00000000..02d4d377 --- /dev/null +++ b/src/test/resources/pyyaml/no-block-collection-end.loader-error @@ -0,0 +1,3 @@ +- foo +- bar +baz: bar diff --git a/src/test/resources/pyyaml/no-block-mapping-end-2.loader-error b/src/test/resources/pyyaml/no-block-mapping-end-2.loader-error new file mode 100644 index 00000000..be63571f --- /dev/null +++ b/src/test/resources/pyyaml/no-block-mapping-end-2.loader-error @@ -0,0 +1,3 @@ +? foo +: bar +: baz diff --git a/src/test/resources/pyyaml/no-block-mapping-end.loader-error b/src/test/resources/pyyaml/no-block-mapping-end.loader-error new file mode 100644 index 00000000..1ea921cf --- /dev/null +++ b/src/test/resources/pyyaml/no-block-mapping-end.loader-error @@ -0,0 +1 @@ +foo: "bar" "baz" diff --git a/src/test/resources/pyyaml/no-document-start.loader-error b/src/test/resources/pyyaml/no-document-start.loader-error new file mode 100644 index 00000000..c725ec8b --- /dev/null +++ b/src/test/resources/pyyaml/no-document-start.loader-error @@ -0,0 +1,3 @@ +%YAML 1.1 +# no --- +foo: bar diff --git a/src/test/resources/pyyaml/no-flow-mapping-end.loader-error b/src/test/resources/pyyaml/no-flow-mapping-end.loader-error new file mode 100644 index 00000000..8bd1403f --- /dev/null +++ b/src/test/resources/pyyaml/no-flow-mapping-end.loader-error @@ -0,0 +1 @@ +{ foo: bar ] diff --git a/src/test/resources/pyyaml/no-flow-sequence-end.loader-error b/src/test/resources/pyyaml/no-flow-sequence-end.loader-error new file mode 100644 index 00000000..750d973b --- /dev/null +++ b/src/test/resources/pyyaml/no-flow-sequence-end.loader-error @@ -0,0 +1 @@ +[foo, bar} diff --git a/src/test/resources/pyyaml/no-node-1.loader-error b/src/test/resources/pyyaml/no-node-1.loader-error new file mode 100644 index 00000000..07b15009 --- /dev/null +++ b/src/test/resources/pyyaml/no-node-1.loader-error @@ -0,0 +1 @@ +- !foo ] diff --git a/src/test/resources/pyyaml/no-node-2.loader-error b/src/test/resources/pyyaml/no-node-2.loader-error new file mode 100644 index 00000000..563e3b34 --- /dev/null +++ b/src/test/resources/pyyaml/no-node-2.loader-error @@ -0,0 +1 @@ +- [ !foo } ] diff --git a/src/test/resources/pyyaml/no-tag.emitter-error b/src/test/resources/pyyaml/no-tag.emitter-error new file mode 100644 index 00000000..384c62f0 --- /dev/null +++ b/src/test/resources/pyyaml/no-tag.emitter-error @@ -0,0 +1,5 @@ +- !StreamStart +- !DocumentStart +- !Scalar { value: 'foo', implicit: [false,false] } +- !DocumentEnd +- !StreamEnd diff --git a/src/test/resources/pyyaml/null.data b/src/test/resources/pyyaml/null.data new file mode 100644 index 00000000..ad125286 --- /dev/null +++ b/src/test/resources/pyyaml/null.data @@ -0,0 +1,3 @@ +- +- ~ +- null diff --git a/src/test/resources/pyyaml/odd-utf16.stream-error b/src/test/resources/pyyaml/odd-utf16.stream-error Binary files differnew file mode 100644 index 00000000..37da060a --- /dev/null +++ b/src/test/resources/pyyaml/odd-utf16.stream-error diff --git a/src/test/resources/pyyaml/remove-possible-simple-key-bug.loader-error b/src/test/resources/pyyaml/remove-possible-simple-key-bug.loader-error new file mode 100644 index 00000000..fe1bc6c5 --- /dev/null +++ b/src/test/resources/pyyaml/remove-possible-simple-key-bug.loader-error @@ -0,0 +1,3 @@ +foo: &A bar +*A ] # The ']' indicator triggers remove_possible_simple_key, + # which should raise an error. diff --git a/src/test/resources/pyyaml/resolver.data b/src/test/resources/pyyaml/resolver.data new file mode 100644 index 00000000..a2964048 --- /dev/null +++ b/src/test/resources/pyyaml/resolver.data @@ -0,0 +1,30 @@ +--- +"this scalar should be selected" +--- +key11: !foo + key12: + is: [selected] + key22: + key13: [not, selected] + key23: [not, selected] + key32: + key31: [not, selected] + key32: [not, selected] + key33: {not: selected} +key21: !bar + - not selected + - selected + - not selected +key31: !baz + key12: + key13: + key14: {selected} + key23: + key14: [not, selected] + key33: + key14: {selected} + key24: {not: selected} + key22: + - key14: {selected} + key24: {not: selected} + - key14: {selected} diff --git a/src/test/resources/pyyaml/run-parser-crash-bug.data b/src/test/resources/pyyaml/run-parser-crash-bug.data new file mode 100644 index 00000000..fe017342 --- /dev/null +++ b/src/test/resources/pyyaml/run-parser-crash-bug.data @@ -0,0 +1,8 @@ +--- +- Harry Potter and the Prisoner of Azkaban +- Harry Potter and the Goblet of Fire +- Harry Potter and the Order of the Phoenix +--- +- Memoirs Found in a Bathtub +- Snow Crash +- Ghost World diff --git a/src/test/resources/pyyaml/scalars.events b/src/test/resources/pyyaml/scalars.events new file mode 100644 index 00000000..32c40f46 --- /dev/null +++ b/src/test/resources/pyyaml/scalars.events @@ -0,0 +1,28 @@ +- !StreamStart + +- !DocumentStart +- !MappingStart +- !Scalar { implicit: [true,true], value: 'empty scalar' } +- !Scalar { implicit: [true,false], value: '' } +- !Scalar { implicit: [true,true], value: 'implicit scalar' } +- !Scalar { implicit: [true,true], value: 'data' } +- !Scalar { implicit: [true,true], value: 'quoted scalar' } +- !Scalar { value: 'data', style: '"' } +- !Scalar { implicit: [true,true], value: 'block scalar' } +- !Scalar { value: 'data', style: '|' } +- !Scalar { implicit: [true,true], value: 'empty scalar with tag' } +- !Scalar { implicit: [false,false], tag: '!mytag', value: '' } +- !Scalar { implicit: [true,true], value: 'implicit scalar with tag' } +- !Scalar { implicit: [false,false], tag: '!mytag', value: 'data' } +- !Scalar { implicit: [true,true], value: 'quoted scalar with tag' } +- !Scalar { value: 'data', style: '"', tag: '!mytag', implicit: [false,false] } +- !Scalar { implicit: [true,true], value: 'block scalar with tag' } +- !Scalar { value: 'data', style: '|', tag: '!mytag', implicit: [false,false] } +- !Scalar { implicit: [true,true], value: 'single character' } +- !Scalar { value: 'a', implicit: [true,true] } +- !Scalar { implicit: [true,true], value: 'single digit' } +- !Scalar { value: '1', implicit: [true,false] } +- !MappingEnd +- !DocumentEnd + +- !StreamEnd diff --git a/src/test/resources/pyyaml/scan-document-end-bug.canonical b/src/test/resources/pyyaml/scan-document-end-bug.canonical new file mode 100644 index 00000000..4a0e8a82 --- /dev/null +++ b/src/test/resources/pyyaml/scan-document-end-bug.canonical @@ -0,0 +1,3 @@ +%YAML 1.1 +--- +!!null "" diff --git a/src/test/resources/pyyaml/scan-document-end-bug.data b/src/test/resources/pyyaml/scan-document-end-bug.data new file mode 100644 index 00000000..3c70543b --- /dev/null +++ b/src/test/resources/pyyaml/scan-document-end-bug.data @@ -0,0 +1,3 @@ +# Ticket #4 +--- +...
\ No newline at end of file diff --git a/src/test/resources/pyyaml/scan-line-break-bug.canonical b/src/test/resources/pyyaml/scan-line-break-bug.canonical new file mode 100644 index 00000000..79f08b74 --- /dev/null +++ b/src/test/resources/pyyaml/scan-line-break-bug.canonical @@ -0,0 +1,3 @@ +%YAML 1.1 +--- +!!map { ? !!str "foo" : !!str "bar baz" } diff --git a/src/test/resources/pyyaml/scan-line-break-bug.data b/src/test/resources/pyyaml/scan-line-break-bug.data new file mode 100644 index 00000000..c974fab0 --- /dev/null +++ b/src/test/resources/pyyaml/scan-line-break-bug.data @@ -0,0 +1,3 @@ +foo:
+ bar
+ baz
diff --git a/src/test/resources/pyyaml/sequences.events b/src/test/resources/pyyaml/sequences.events new file mode 100644 index 00000000..692a3290 --- /dev/null +++ b/src/test/resources/pyyaml/sequences.events @@ -0,0 +1,81 @@ +- !StreamStart + +- !DocumentStart +- !SequenceStart +- !SequenceEnd +- !DocumentEnd + +- !DocumentStart +- !SequenceStart { tag: '!mytag', implicit: false } +- !SequenceEnd +- !DocumentEnd + +- !DocumentStart +- !SequenceStart +- !SequenceStart +- !SequenceEnd +- !SequenceStart { tag: '!mytag', implicit: false } +- !SequenceEnd +- !SequenceStart +- !Scalar +- !Scalar { value: 'data' } +- !Scalar { tag: '!mytag', implicit: [false,false], value: 'data' } +- !SequenceEnd +- !SequenceStart +- !SequenceStart +- !SequenceStart +- !Scalar +- !SequenceEnd +- !SequenceEnd +- !SequenceEnd +- !SequenceStart +- !SequenceStart { tag: '!mytag', implicit: false } +- !SequenceStart +- !Scalar { value: 'data' } +- !SequenceEnd +- !SequenceEnd +- !SequenceEnd +- !SequenceEnd +- !DocumentEnd + +- !DocumentStart +- !SequenceStart +- !MappingStart +- !Scalar { value: 'key1' } +- !SequenceStart +- !Scalar { value: 'data1' } +- !Scalar { value: 'data2' } +- !SequenceEnd +- !Scalar { value: 'key2' } +- !SequenceStart { tag: '!mytag1', implicit: false } +- !Scalar { value: 'data3' } +- !SequenceStart +- !Scalar { value: 'data4' } +- !Scalar { value: 'data5' } +- !SequenceEnd +- !SequenceStart { tag: '!mytag2', implicit: false } +- !Scalar { value: 'data6' } +- !Scalar { value: 'data7' } +- !SequenceEnd +- !SequenceEnd +- !MappingEnd +- !SequenceEnd +- !DocumentEnd + +- !DocumentStart +- !SequenceStart +- !SequenceStart { flow_style: true } +- !SequenceStart +- !SequenceEnd +- !Scalar +- !Scalar { value: 'data' } +- !Scalar { tag: '!mytag', implicit: [false,false], value: 'data' } +- !SequenceStart { tag: '!mytag', implicit: false } +- !Scalar { value: 'data' } +- !Scalar { value: 'data' } +- !SequenceEnd +- !SequenceEnd +- !SequenceEnd +- !DocumentEnd + +- !StreamEnd diff --git a/src/test/resources/pyyaml/single-dot-is-not-float-bug.data b/src/test/resources/pyyaml/single-dot-is-not-float-bug.data new file mode 100644 index 00000000..9c558e35 --- /dev/null +++ b/src/test/resources/pyyaml/single-dot-is-not-float-bug.data @@ -0,0 +1 @@ +. diff --git a/src/test/resources/pyyaml/sloppy-indentation.canonical b/src/test/resources/pyyaml/sloppy-indentation.canonical new file mode 100644 index 00000000..438bc04a --- /dev/null +++ b/src/test/resources/pyyaml/sloppy-indentation.canonical @@ -0,0 +1,18 @@ +%YAML 1.1 +--- +!!map { + ? !!str "in the block context" + : !!map { + ? !!str "indentation should be kept" + : !!map { + ? !!str "but in the flow context" + : !!seq [ !!str "it may be violated" ] + } + } +} +--- !!str +"the parser does not require scalars to be indented with at least one space" +--- !!str +"the parser does not require scalars to be indented with at least one space" +--- !!map +{ ? !!str "foo": { ? !!str "bar" : !!str "quoted scalars may not adhere indentation" } } diff --git a/src/test/resources/pyyaml/sloppy-indentation.data b/src/test/resources/pyyaml/sloppy-indentation.data new file mode 100644 index 00000000..2eb4f5a5 --- /dev/null +++ b/src/test/resources/pyyaml/sloppy-indentation.data @@ -0,0 +1,17 @@ +--- +in the block context: + indentation should be kept: { + but in the flow context: [ +it may be violated] +} +--- +the parser does not require scalars +to be indented with at least one space +... +--- +"the parser does not require scalars +to be indented with at least one space" +--- +foo: + bar: 'quoted scalars +may not adhere indentation' diff --git a/src/test/resources/pyyaml/spec-02-01.data b/src/test/resources/pyyaml/spec-02-01.data new file mode 100644 index 00000000..d12e6711 --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-01.data @@ -0,0 +1,3 @@ +- Mark McGwire +- Sammy Sosa +- Ken Griffey diff --git a/src/test/resources/pyyaml/spec-02-01.tokens b/src/test/resources/pyyaml/spec-02-01.tokens new file mode 100644 index 00000000..ce44caca --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-01.tokens @@ -0,0 +1 @@ +[[ , _ , _ , _ ]} diff --git a/src/test/resources/pyyaml/spec-02-02.data b/src/test/resources/pyyaml/spec-02-02.data new file mode 100644 index 00000000..7b7ec948 --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-02.data @@ -0,0 +1,3 @@ +hr: 65 # Home runs +avg: 0.278 # Batting average +rbi: 147 # Runs Batted In diff --git a/src/test/resources/pyyaml/spec-02-02.tokens b/src/test/resources/pyyaml/spec-02-02.tokens new file mode 100644 index 00000000..e4e381b4 --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-02.tokens @@ -0,0 +1,5 @@ +{{ +? _ : _ +? _ : _ +? _ : _ +]} diff --git a/src/test/resources/pyyaml/spec-02-03.data b/src/test/resources/pyyaml/spec-02-03.data new file mode 100644 index 00000000..656d628e --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-03.data @@ -0,0 +1,8 @@ +american: + - Boston Red Sox + - Detroit Tigers + - New York Yankees +national: + - New York Mets + - Chicago Cubs + - Atlanta Braves diff --git a/src/test/resources/pyyaml/spec-02-03.tokens b/src/test/resources/pyyaml/spec-02-03.tokens new file mode 100644 index 00000000..89815f29 --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-03.tokens @@ -0,0 +1,4 @@ +{{ +? _ : [[ , _ , _ , _ ]} +? _ : [[ , _ , _ , _ ]} +]} diff --git a/src/test/resources/pyyaml/spec-02-04.data b/src/test/resources/pyyaml/spec-02-04.data new file mode 100644 index 00000000..430f6b3d --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-04.data @@ -0,0 +1,8 @@ +- + name: Mark McGwire + hr: 65 + avg: 0.278 +- + name: Sammy Sosa + hr: 63 + avg: 0.288 diff --git a/src/test/resources/pyyaml/spec-02-04.tokens b/src/test/resources/pyyaml/spec-02-04.tokens new file mode 100644 index 00000000..9cb98156 --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-04.tokens @@ -0,0 +1,4 @@ +[[ +, {{ ? _ : _ ? _ : _ ? _ : _ ]} +, {{ ? _ : _ ? _ : _ ? _ : _ ]} +]} diff --git a/src/test/resources/pyyaml/spec-02-05.data b/src/test/resources/pyyaml/spec-02-05.data new file mode 100644 index 00000000..cdd77706 --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-05.data @@ -0,0 +1,3 @@ +- [name , hr, avg ] +- [Mark McGwire, 65, 0.278] +- [Sammy Sosa , 63, 0.288] diff --git a/src/test/resources/pyyaml/spec-02-05.tokens b/src/test/resources/pyyaml/spec-02-05.tokens new file mode 100644 index 00000000..3f6f1ab5 --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-05.tokens @@ -0,0 +1,5 @@ +[[ +, [ _ , _ , _ ] +, [ _ , _ , _ ] +, [ _ , _ , _ ] +]} diff --git a/src/test/resources/pyyaml/spec-02-06.data b/src/test/resources/pyyaml/spec-02-06.data new file mode 100644 index 00000000..7a957b23 --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-06.data @@ -0,0 +1,5 @@ +Mark McGwire: {hr: 65, avg: 0.278} +Sammy Sosa: { + hr: 63, + avg: 0.288 + } diff --git a/src/test/resources/pyyaml/spec-02-06.tokens b/src/test/resources/pyyaml/spec-02-06.tokens new file mode 100644 index 00000000..a1a5eef2 --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-06.tokens @@ -0,0 +1,4 @@ +{{ +? _ : { ? _ : _ , ? _ : _ } +? _ : { ? _ : _ , ? _ : _ } +]} diff --git a/src/test/resources/pyyaml/spec-02-07.data b/src/test/resources/pyyaml/spec-02-07.data new file mode 100644 index 00000000..bc711d54 --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-07.data @@ -0,0 +1,10 @@ +# Ranking of 1998 home runs +--- +- Mark McGwire +- Sammy Sosa +- Ken Griffey + +# Team ranking +--- +- Chicago Cubs +- St Louis Cardinals diff --git a/src/test/resources/pyyaml/spec-02-07.tokens b/src/test/resources/pyyaml/spec-02-07.tokens new file mode 100644 index 00000000..ed48883c --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-07.tokens @@ -0,0 +1,12 @@ +--- +[[ +, _ +, _ +, _ +]} + +--- +[[ +, _ +, _ +]} diff --git a/src/test/resources/pyyaml/spec-02-08.data b/src/test/resources/pyyaml/spec-02-08.data new file mode 100644 index 00000000..05e102d8 --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-08.data @@ -0,0 +1,10 @@ +--- +time: 20:03:20 +player: Sammy Sosa +action: strike (miss) +... +--- +time: 20:03:47 +player: Sammy Sosa +action: grand slam +... diff --git a/src/test/resources/pyyaml/spec-02-08.tokens b/src/test/resources/pyyaml/spec-02-08.tokens new file mode 100644 index 00000000..7d2c03df --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-08.tokens @@ -0,0 +1,15 @@ +--- +{{ +? _ : _ +? _ : _ +? _ : _ +]} +... + +--- +{{ +? _ : _ +? _ : _ +? _ : _ +]} +... diff --git a/src/test/resources/pyyaml/spec-02-09.data b/src/test/resources/pyyaml/spec-02-09.data new file mode 100644 index 00000000..e2641805 --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-09.data @@ -0,0 +1,8 @@ +--- +hr: # 1998 hr ranking + - Mark McGwire + - Sammy Sosa +rbi: + # 1998 rbi ranking + - Sammy Sosa + - Ken Griffey diff --git a/src/test/resources/pyyaml/spec-02-09.tokens b/src/test/resources/pyyaml/spec-02-09.tokens new file mode 100644 index 00000000..b2ec10ea --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-09.tokens @@ -0,0 +1,5 @@ +--- +{{ +? _ : [[ , _ , _ ]} +? _ : [[ , _ , _ ]} +]} diff --git a/src/test/resources/pyyaml/spec-02-10.data b/src/test/resources/pyyaml/spec-02-10.data new file mode 100644 index 00000000..61808f67 --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-10.data @@ -0,0 +1,8 @@ +--- +hr: + - Mark McGwire + # Following node labeled SS + - &SS Sammy Sosa +rbi: + - *SS # Subsequent occurrence + - Ken Griffey diff --git a/src/test/resources/pyyaml/spec-02-10.tokens b/src/test/resources/pyyaml/spec-02-10.tokens new file mode 100644 index 00000000..26caa2b1 --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-10.tokens @@ -0,0 +1,5 @@ +--- +{{ +? _ : [[ , _ , & _ ]} +? _ : [[ , * , _ ]} +]} diff --git a/src/test/resources/pyyaml/spec-02-11.data b/src/test/resources/pyyaml/spec-02-11.data new file mode 100644 index 00000000..9123ce21 --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-11.data @@ -0,0 +1,9 @@ +? - Detroit Tigers + - Chicago cubs +: + - 2001-07-23 + +? [ New York Yankees, + Atlanta Braves ] +: [ 2001-07-02, 2001-08-12, + 2001-08-14 ] diff --git a/src/test/resources/pyyaml/spec-02-11.tokens b/src/test/resources/pyyaml/spec-02-11.tokens new file mode 100644 index 00000000..fe242033 --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-11.tokens @@ -0,0 +1,6 @@ +{{ +? [[ , _ , _ ]} +: [[ , _ ]} +? [ _ , _ ] +: [ _ , _ , _ ] +]} diff --git a/src/test/resources/pyyaml/spec-02-12.data b/src/test/resources/pyyaml/spec-02-12.data new file mode 100644 index 00000000..1fc33f9d --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-12.data @@ -0,0 +1,8 @@ +--- +# products purchased +- item : Super Hoop + quantity: 1 +- item : Basketball + quantity: 4 +- item : Big Shoes + quantity: 1 diff --git a/src/test/resources/pyyaml/spec-02-12.tokens b/src/test/resources/pyyaml/spec-02-12.tokens new file mode 100644 index 00000000..ea21e506 --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-12.tokens @@ -0,0 +1,6 @@ +--- +[[ +, {{ ? _ : _ ? _ : _ ]} +, {{ ? _ : _ ? _ : _ ]} +, {{ ? _ : _ ? _ : _ ]} +]} diff --git a/src/test/resources/pyyaml/spec-02-13.data b/src/test/resources/pyyaml/spec-02-13.data new file mode 100644 index 00000000..13fb6560 --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-13.data @@ -0,0 +1,4 @@ +# ASCII Art +--- | + \//||\/|| + // || ||__ diff --git a/src/test/resources/pyyaml/spec-02-13.tokens b/src/test/resources/pyyaml/spec-02-13.tokens new file mode 100644 index 00000000..7456c055 --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-13.tokens @@ -0,0 +1 @@ +--- _ diff --git a/src/test/resources/pyyaml/spec-02-14.data b/src/test/resources/pyyaml/spec-02-14.data new file mode 100644 index 00000000..59943def --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-14.data @@ -0,0 +1,4 @@ +--- + Mark McGwire's + year was crippled + by a knee injury. diff --git a/src/test/resources/pyyaml/spec-02-14.tokens b/src/test/resources/pyyaml/spec-02-14.tokens new file mode 100644 index 00000000..7456c055 --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-14.tokens @@ -0,0 +1 @@ +--- _ diff --git a/src/test/resources/pyyaml/spec-02-15.data b/src/test/resources/pyyaml/spec-02-15.data new file mode 100644 index 00000000..80b89a6d --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-15.data @@ -0,0 +1,8 @@ +> + Sammy Sosa completed another + fine season with great stats. + + 63 Home Runs + 0.288 Batting Average + + What a year! diff --git a/src/test/resources/pyyaml/spec-02-15.tokens b/src/test/resources/pyyaml/spec-02-15.tokens new file mode 100644 index 00000000..31354ec1 --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-15.tokens @@ -0,0 +1 @@ +_ diff --git a/src/test/resources/pyyaml/spec-02-16.data b/src/test/resources/pyyaml/spec-02-16.data new file mode 100644 index 00000000..9f66d881 --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-16.data @@ -0,0 +1,7 @@ +name: Mark McGwire +accomplishment: > + Mark set a major league + home run record in 1998. +stats: | + 65 Home Runs + 0.278 Batting Average diff --git a/src/test/resources/pyyaml/spec-02-16.tokens b/src/test/resources/pyyaml/spec-02-16.tokens new file mode 100644 index 00000000..e4e381b4 --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-16.tokens @@ -0,0 +1,5 @@ +{{ +? _ : _ +? _ : _ +? _ : _ +]} diff --git a/src/test/resources/pyyaml/spec-02-17.data b/src/test/resources/pyyaml/spec-02-17.data new file mode 100644 index 00000000..3e899c08 --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-17.data @@ -0,0 +1,7 @@ +unicode: "Sosa did fine.\u263A" +control: "\b1998\t1999\t2000\n" +hexesc: "\x0D\x0A is \r\n" + +single: '"Howdy!" he cried.' +quoted: ' # not a ''comment''.' +tie-fighter: '|\-*-/|' diff --git a/src/test/resources/pyyaml/spec-02-17.tokens b/src/test/resources/pyyaml/spec-02-17.tokens new file mode 100644 index 00000000..db655402 --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-17.tokens @@ -0,0 +1,8 @@ +{{ +? _ : _ +? _ : _ +? _ : _ +? _ : _ +? _ : _ +? _ : _ +]} diff --git a/src/test/resources/pyyaml/spec-02-18.data b/src/test/resources/pyyaml/spec-02-18.data new file mode 100644 index 00000000..e0a8bfa9 --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-18.data @@ -0,0 +1,6 @@ +plain: + This unquoted scalar + spans many lines. + +quoted: "So does this + quoted scalar.\n" diff --git a/src/test/resources/pyyaml/spec-02-18.tokens b/src/test/resources/pyyaml/spec-02-18.tokens new file mode 100644 index 00000000..83b31dc0 --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-18.tokens @@ -0,0 +1,4 @@ +{{ +? _ : _ +? _ : _ +]} diff --git a/src/test/resources/pyyaml/spec-02-19.data b/src/test/resources/pyyaml/spec-02-19.data new file mode 100644 index 00000000..bf69de69 --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-19.data @@ -0,0 +1,5 @@ +canonical: 12345 +decimal: +12,345 +sexagesimal: 3:25:45 +octal: 014 +hexadecimal: 0xC diff --git a/src/test/resources/pyyaml/spec-02-19.tokens b/src/test/resources/pyyaml/spec-02-19.tokens new file mode 100644 index 00000000..5bda68f4 --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-19.tokens @@ -0,0 +1,7 @@ +{{ +? _ : _ +? _ : _ +? _ : _ +? _ : _ +? _ : _ +]} diff --git a/src/test/resources/pyyaml/spec-02-20.data b/src/test/resources/pyyaml/spec-02-20.data new file mode 100644 index 00000000..1d4897ff --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-20.data @@ -0,0 +1,6 @@ +canonical: 1.23015e+3 +exponential: 12.3015e+02 +sexagesimal: 20:30.15 +fixed: 1,230.15 +negative infinity: -.inf +not a number: .NaN diff --git a/src/test/resources/pyyaml/spec-02-20.tokens b/src/test/resources/pyyaml/spec-02-20.tokens new file mode 100644 index 00000000..db655402 --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-20.tokens @@ -0,0 +1,8 @@ +{{ +? _ : _ +? _ : _ +? _ : _ +? _ : _ +? _ : _ +? _ : _ +]} diff --git a/src/test/resources/pyyaml/spec-02-21.data b/src/test/resources/pyyaml/spec-02-21.data new file mode 100644 index 00000000..dec6a56b --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-21.data @@ -0,0 +1,4 @@ +null: ~ +true: y +false: n +string: '12345' diff --git a/src/test/resources/pyyaml/spec-02-21.tokens b/src/test/resources/pyyaml/spec-02-21.tokens new file mode 100644 index 00000000..aeccbaf6 --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-21.tokens @@ -0,0 +1,6 @@ +{{ +? _ : _ +? _ : _ +? _ : _ +? _ : _ +]} diff --git a/src/test/resources/pyyaml/spec-02-22.data b/src/test/resources/pyyaml/spec-02-22.data new file mode 100644 index 00000000..aaac185a --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-22.data @@ -0,0 +1,4 @@ +canonical: 2001-12-15T02:59:43.1Z +iso8601: 2001-12-14t21:59:43.10-05:00 +spaced: 2001-12-14 21:59:43.10 -5 +date: 2002-12-14 diff --git a/src/test/resources/pyyaml/spec-02-22.tokens b/src/test/resources/pyyaml/spec-02-22.tokens new file mode 100644 index 00000000..aeccbaf6 --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-22.tokens @@ -0,0 +1,6 @@ +{{ +? _ : _ +? _ : _ +? _ : _ +? _ : _ +]} diff --git a/src/test/resources/pyyaml/spec-02-23.data b/src/test/resources/pyyaml/spec-02-23.data new file mode 100644 index 00000000..5dbd992d --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-23.data @@ -0,0 +1,13 @@ +--- +not-date: !!str 2002-04-28 + +picture: !!binary | + R0lGODlhDAAMAIQAAP//9/X + 17unp5WZmZgAAAOfn515eXv + Pz7Y6OjuDg4J+fn5OTk6enp + 56enmleECcgggoBADs= + +application specific tag: !something | + The semantics of the tag + above may be different for + different documents. diff --git a/src/test/resources/pyyaml/spec-02-23.tokens b/src/test/resources/pyyaml/spec-02-23.tokens new file mode 100644 index 00000000..9ac54aad --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-23.tokens @@ -0,0 +1,6 @@ +--- +{{ +? _ : ! _ +? _ : ! _ +? _ : ! _ +]} diff --git a/src/test/resources/pyyaml/spec-02-24.data b/src/test/resources/pyyaml/spec-02-24.data new file mode 100644 index 00000000..1180757d --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-24.data @@ -0,0 +1,14 @@ +%TAG ! tag:clarkevans.com,2002: +--- !shape + # Use the ! handle for presenting + # tag:clarkevans.com,2002:circle +- !circle + center: &ORIGIN {x: 73, y: 129} + radius: 7 +- !line + start: *ORIGIN + finish: { x: 89, y: 102 } +- !label + start: *ORIGIN + color: 0xFFEEBB + text: Pretty vector drawing. diff --git a/src/test/resources/pyyaml/spec-02-24.tokens b/src/test/resources/pyyaml/spec-02-24.tokens new file mode 100644 index 00000000..039c3857 --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-24.tokens @@ -0,0 +1,20 @@ +% +--- ! +[[ +, ! + {{ + ? _ : & { ? _ : _ , ? _ : _ } + ? _ : _ + ]} +, ! + {{ + ? _ : * + ? _ : { ? _ : _ , ? _ : _ } + ]} +, ! + {{ + ? _ : * + ? _ : _ + ? _ : _ + ]} +]} diff --git a/src/test/resources/pyyaml/spec-02-25.data b/src/test/resources/pyyaml/spec-02-25.data new file mode 100644 index 00000000..769ac319 --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-25.data @@ -0,0 +1,7 @@ +# sets are represented as a +# mapping where each key is +# associated with the empty string +--- !!set +? Mark McGwire +? Sammy Sosa +? Ken Griff diff --git a/src/test/resources/pyyaml/spec-02-25.tokens b/src/test/resources/pyyaml/spec-02-25.tokens new file mode 100644 index 00000000..b7002368 --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-25.tokens @@ -0,0 +1,6 @@ +--- ! +{{ +? _ +? _ +? _ +]} diff --git a/src/test/resources/pyyaml/spec-02-26.data b/src/test/resources/pyyaml/spec-02-26.data new file mode 100644 index 00000000..3143763d --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-26.data @@ -0,0 +1,7 @@ +# ordered maps are represented as +# a sequence of mappings, with +# each mapping having one key +--- !!omap +- Mark McGwire: 65 +- Sammy Sosa: 63 +- Ken Griffy: 58 diff --git a/src/test/resources/pyyaml/spec-02-26.tokens b/src/test/resources/pyyaml/spec-02-26.tokens new file mode 100644 index 00000000..7bee4920 --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-26.tokens @@ -0,0 +1,6 @@ +--- ! +[[ +, {{ ? _ : _ ]} +, {{ ? _ : _ ]} +, {{ ? _ : _ ]} +]} diff --git a/src/test/resources/pyyaml/spec-02-27.data b/src/test/resources/pyyaml/spec-02-27.data new file mode 100644 index 00000000..4625739d --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-27.data @@ -0,0 +1,29 @@ +--- !<tag:clarkevans.com,2002:invoice> +invoice: 34843 +date : 2001-01-23 +bill-to: &id001 + given : Chris + family : Dumars + address: + lines: | + 458 Walkman Dr. + Suite #292 + city : Royal Oak + state : MI + postal : 48046 +ship-to: *id001 +product: + - sku : BL394D + quantity : 4 + description : Basketball + price : 450.00 + - sku : BL4438H + quantity : 1 + description : Super Hoop + price : 2392.00 +tax : 251.42 +total: 4443.52 +comments: + Late afternoon is best. + Backup contact is Nancy + Billsmer @ 338-4338. diff --git a/src/test/resources/pyyaml/spec-02-27.tokens b/src/test/resources/pyyaml/spec-02-27.tokens new file mode 100644 index 00000000..2dc1c25d --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-27.tokens @@ -0,0 +1,20 @@ +--- ! +{{ +? _ : _ +? _ : _ +? _ : & + {{ + ? _ : _ + ? _ : _ + ? _ : {{ ? _ : _ ? _ : _ ? _ : _ ? _ : _ ]} + ]} +? _ : * +? _ : + [[ + , {{ ? _ : _ ? _ : _ ? _ : _ ? _ : _ ]} + , {{ ? _ : _ ? _ : _ ? _ : _ ? _ : _ ]} + ]} +? _ : _ +? _ : _ +? _ : _ +]} diff --git a/src/test/resources/pyyaml/spec-02-28.data b/src/test/resources/pyyaml/spec-02-28.data new file mode 100644 index 00000000..a5c8dc85 --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-28.data @@ -0,0 +1,26 @@ +--- +Time: 2001-11-23 15:01:42 -5 +User: ed +Warning: + This is an error message + for the log file +--- +Time: 2001-11-23 15:02:31 -5 +User: ed +Warning: + A slightly different error + message. +--- +Date: 2001-11-23 15:03:17 -5 +User: ed +Fatal: + Unknown variable "bar" +Stack: + - file: TopClass.py + line: 23 + code: | + x = MoreObject("345\n") + - file: MoreClass.py + line: 58 + code: |- + foo = bar diff --git a/src/test/resources/pyyaml/spec-02-28.tokens b/src/test/resources/pyyaml/spec-02-28.tokens new file mode 100644 index 00000000..8d5e1bc5 --- /dev/null +++ b/src/test/resources/pyyaml/spec-02-28.tokens @@ -0,0 +1,23 @@ +--- +{{ +? _ : _ +? _ : _ +? _ : _ +]} +--- +{{ +? _ : _ +? _ : _ +? _ : _ +]} +--- +{{ +? _ : _ +? _ : _ +? _ : _ +? _ : + [[ + , {{ ? _ : _ ? _ : _ ? _ : _ ]} + , {{ ? _ : _ ? _ : _ ? _ : _ ]} + ]} +]} diff --git a/src/test/resources/pyyaml/spec-05-01-utf16be.data b/src/test/resources/pyyaml/spec-05-01-utf16be.data Binary files differnew file mode 100644 index 00000000..35250629 --- /dev/null +++ b/src/test/resources/pyyaml/spec-05-01-utf16be.data diff --git a/src/test/resources/pyyaml/spec-05-01-utf16le.data b/src/test/resources/pyyaml/spec-05-01-utf16le.data Binary files differnew file mode 100644 index 00000000..0823f749 --- /dev/null +++ b/src/test/resources/pyyaml/spec-05-01-utf16le.data diff --git a/src/test/resources/pyyaml/spec-05-01-utf8.data b/src/test/resources/pyyaml/spec-05-01-utf8.data new file mode 100644 index 00000000..780d25bf --- /dev/null +++ b/src/test/resources/pyyaml/spec-05-01-utf8.data @@ -0,0 +1 @@ +# Comment only. diff --git a/src/test/resources/pyyaml/spec-05-02-utf16be.data b/src/test/resources/pyyaml/spec-05-02-utf16be.data Binary files differnew file mode 100644 index 00000000..5ebbb04e --- /dev/null +++ b/src/test/resources/pyyaml/spec-05-02-utf16be.data diff --git a/src/test/resources/pyyaml/spec-05-02-utf16le.data b/src/test/resources/pyyaml/spec-05-02-utf16le.data Binary files differnew file mode 100644 index 00000000..0cd90a2b --- /dev/null +++ b/src/test/resources/pyyaml/spec-05-02-utf16le.data diff --git a/src/test/resources/pyyaml/spec-05-02-utf8.data b/src/test/resources/pyyaml/spec-05-02-utf8.data new file mode 100644 index 00000000..fb74866f --- /dev/null +++ b/src/test/resources/pyyaml/spec-05-02-utf8.data @@ -0,0 +1,3 @@ +# Invalid use of BOM +# inside a +# document. diff --git a/src/test/resources/pyyaml/spec-05-03.canonical b/src/test/resources/pyyaml/spec-05-03.canonical new file mode 100644 index 00000000..a143a73f --- /dev/null +++ b/src/test/resources/pyyaml/spec-05-03.canonical @@ -0,0 +1,14 @@ +%YAML 1.1 +--- +!!map { + ? !!str "sequence" + : !!seq [ + !!str "one", !!str "two" + ], + ? !!str "mapping" + : !!map { + ? !!str "sky" : !!str "blue", +# ? !!str "sea" : !!str "green", + ? !!map { ? !!str "sea" : !!str "green" } : !!null "", + } +} diff --git a/src/test/resources/pyyaml/spec-05-03.data b/src/test/resources/pyyaml/spec-05-03.data new file mode 100644 index 00000000..4661f333 --- /dev/null +++ b/src/test/resources/pyyaml/spec-05-03.data @@ -0,0 +1,7 @@ +sequence: +- one +- two +mapping: + ? sky + : blue + ? sea : green diff --git a/src/test/resources/pyyaml/spec-05-04.canonical b/src/test/resources/pyyaml/spec-05-04.canonical new file mode 100644 index 00000000..00c97236 --- /dev/null +++ b/src/test/resources/pyyaml/spec-05-04.canonical @@ -0,0 +1,13 @@ +%YAML 1.1 +--- +!!map { + ? !!str "sequence" + : !!seq [ + !!str "one", !!str "two" + ], + ? !!str "mapping" + : !!map { + ? !!str "sky" : !!str "blue", + ? !!str "sea" : !!str "green", + } +} diff --git a/src/test/resources/pyyaml/spec-05-04.data b/src/test/resources/pyyaml/spec-05-04.data new file mode 100644 index 00000000..df338477 --- /dev/null +++ b/src/test/resources/pyyaml/spec-05-04.data @@ -0,0 +1,2 @@ +sequence: [ one, two, ] +mapping: { sky: blue, sea: green } diff --git a/src/test/resources/pyyaml/spec-05-05.data b/src/test/resources/pyyaml/spec-05-05.data new file mode 100644 index 00000000..62524c0d --- /dev/null +++ b/src/test/resources/pyyaml/spec-05-05.data @@ -0,0 +1 @@ +# Comment only. diff --git a/src/test/resources/pyyaml/spec-05-06.canonical b/src/test/resources/pyyaml/spec-05-06.canonical new file mode 100644 index 00000000..4f30c111 --- /dev/null +++ b/src/test/resources/pyyaml/spec-05-06.canonical @@ -0,0 +1,8 @@ +%YAML 1.1 +--- +!!map { + ? !!str "anchored" + : &A1 !local "value", + ? !!str "alias" + : *A1, +} diff --git a/src/test/resources/pyyaml/spec-05-06.data b/src/test/resources/pyyaml/spec-05-06.data new file mode 100644 index 00000000..7a1f9b30 --- /dev/null +++ b/src/test/resources/pyyaml/spec-05-06.data @@ -0,0 +1,2 @@ +anchored: !local &anchor value +alias: *anchor diff --git a/src/test/resources/pyyaml/spec-05-07.canonical b/src/test/resources/pyyaml/spec-05-07.canonical new file mode 100644 index 00000000..dc3732a5 --- /dev/null +++ b/src/test/resources/pyyaml/spec-05-07.canonical @@ -0,0 +1,8 @@ +%YAML 1.1 +--- +!!map { + ? !!str "literal" + : !!str "text\n", + ? !!str "folded" + : !!str "text\n", +} diff --git a/src/test/resources/pyyaml/spec-05-07.data b/src/test/resources/pyyaml/spec-05-07.data new file mode 100644 index 00000000..97eb3a34 --- /dev/null +++ b/src/test/resources/pyyaml/spec-05-07.data @@ -0,0 +1,4 @@ +literal: | + text +folded: > + text diff --git a/src/test/resources/pyyaml/spec-05-08.canonical b/src/test/resources/pyyaml/spec-05-08.canonical new file mode 100644 index 00000000..610bd687 --- /dev/null +++ b/src/test/resources/pyyaml/spec-05-08.canonical @@ -0,0 +1,8 @@ +%YAML 1.1 +--- +!!map { + ? !!str "single" + : !!str "text", + ? !!str "double" + : !!str "text", +} diff --git a/src/test/resources/pyyaml/spec-05-08.data b/src/test/resources/pyyaml/spec-05-08.data new file mode 100644 index 00000000..04ebf691 --- /dev/null +++ b/src/test/resources/pyyaml/spec-05-08.data @@ -0,0 +1,2 @@ +single: 'text' +double: "text" diff --git a/src/test/resources/pyyaml/spec-05-09.canonical b/src/test/resources/pyyaml/spec-05-09.canonical new file mode 100644 index 00000000..597e3dea --- /dev/null +++ b/src/test/resources/pyyaml/spec-05-09.canonical @@ -0,0 +1,3 @@ +%YAML 1.1 +--- +!!str "text" diff --git a/src/test/resources/pyyaml/spec-05-09.data b/src/test/resources/pyyaml/spec-05-09.data new file mode 100644 index 00000000..a43431bd --- /dev/null +++ b/src/test/resources/pyyaml/spec-05-09.data @@ -0,0 +1,2 @@ +%YAML 1.1 +--- text diff --git a/src/test/resources/pyyaml/spec-05-10.data b/src/test/resources/pyyaml/spec-05-10.data new file mode 100644 index 00000000..a4caf911 --- /dev/null +++ b/src/test/resources/pyyaml/spec-05-10.data @@ -0,0 +1,2 @@ +commercial-at: @text +grave-accent: `text diff --git a/src/test/resources/pyyaml/spec-05-11.canonical b/src/test/resources/pyyaml/spec-05-11.canonical new file mode 100644 index 00000000..fc25bef4 --- /dev/null +++ b/src/test/resources/pyyaml/spec-05-11.canonical @@ -0,0 +1,6 @@ +%YAML 1.1 +--- !!str +"Generic line break (no glyph)\n\ + Generic line break (glyphed)\n\ + Line separator\u2028\ + Paragraph separator\u2029" diff --git a/src/test/resources/pyyaml/spec-05-11.data b/src/test/resources/pyyaml/spec-05-11.data new file mode 100644 index 00000000..b448b759 --- /dev/null +++ b/src/test/resources/pyyaml/spec-05-11.data @@ -0,0 +1,3 @@ +| + Generic line break (no glyph) + Generic line break (glyphed)
Line separator
Paragraph separator
\ No newline at end of file diff --git a/src/test/resources/pyyaml/spec-05-12.data b/src/test/resources/pyyaml/spec-05-12.data new file mode 100644 index 00000000..7c3ad7f3 --- /dev/null +++ b/src/test/resources/pyyaml/spec-05-12.data @@ -0,0 +1,9 @@ +# Tabs do's and don'ts: +# comment: +quoted: "Quoted " +block: | + void main() { + printf("Hello, world!\n"); + } +elsewhere: # separation + indentation, in plain scalar diff --git a/src/test/resources/pyyaml/spec-05-13.canonical b/src/test/resources/pyyaml/spec-05-13.canonical new file mode 100644 index 00000000..90c1c5c3 --- /dev/null +++ b/src/test/resources/pyyaml/spec-05-13.canonical @@ -0,0 +1,5 @@ +%YAML 1.1 +--- !!str +"Text containing \ + both space and \ + tab characters" diff --git a/src/test/resources/pyyaml/spec-05-13.data b/src/test/resources/pyyaml/spec-05-13.data new file mode 100644 index 00000000..fce7951c --- /dev/null +++ b/src/test/resources/pyyaml/spec-05-13.data @@ -0,0 +1,3 @@ + "Text containing + both space and + tab characters" diff --git a/src/test/resources/pyyaml/spec-05-14.canonical b/src/test/resources/pyyaml/spec-05-14.canonical new file mode 100644 index 00000000..4bff01cb --- /dev/null +++ b/src/test/resources/pyyaml/spec-05-14.canonical @@ -0,0 +1,7 @@ +%YAML 1.1 +--- +"Fun with \x5C + \x22 \x07 \x08 \x1B \x0C + \x0A \x0D \x09 \x0B \x00 + \x20 \xA0 \x85 \u2028 \u2029 + A A A" diff --git a/src/test/resources/pyyaml/spec-05-14.data b/src/test/resources/pyyaml/spec-05-14.data new file mode 100644 index 00000000..d6e8ce49 --- /dev/null +++ b/src/test/resources/pyyaml/spec-05-14.data @@ -0,0 +1,2 @@ +"Fun with \\ + \" \a \b \e \f \
\n \r \t \v \0 \
\ \_ \N \L \P \
\x41 \u0041 \U00000041" diff --git a/src/test/resources/pyyaml/spec-05-15.data b/src/test/resources/pyyaml/spec-05-15.data new file mode 100644 index 00000000..7bf12b6c --- /dev/null +++ b/src/test/resources/pyyaml/spec-05-15.data @@ -0,0 +1,3 @@ +Bad escapes: + "\c + \xq-" diff --git a/src/test/resources/pyyaml/spec-06-01.canonical b/src/test/resources/pyyaml/spec-06-01.canonical new file mode 100644 index 00000000..f17ec922 --- /dev/null +++ b/src/test/resources/pyyaml/spec-06-01.canonical @@ -0,0 +1,15 @@ +%YAML 1.1 +--- +!!map { + ? !!str "Not indented" + : !!map { + ? !!str "By one space" + : !!str "By four\n spaces\n", + ? !!str "Flow style" + : !!seq [ + !!str "By two", + !!str "Also by two", + !!str "Still by two", + ] + } +} diff --git a/src/test/resources/pyyaml/spec-06-01.data b/src/test/resources/pyyaml/spec-06-01.data new file mode 100644 index 00000000..6134ba12 --- /dev/null +++ b/src/test/resources/pyyaml/spec-06-01.data @@ -0,0 +1,14 @@ + # Leading comment line spaces are + # neither content nor indentation. + +Not indented: + By one space: | + By four + spaces + Flow style: [ # Leading spaces + By two, # in flow style + Also by two, # are neither +# Tabs are not allowed: +# Still by two # content nor + Still by two # content nor + ] # indentation. diff --git a/src/test/resources/pyyaml/spec-06-02.data b/src/test/resources/pyyaml/spec-06-02.data new file mode 100644 index 00000000..ff741e5f --- /dev/null +++ b/src/test/resources/pyyaml/spec-06-02.data @@ -0,0 +1,3 @@ + # Comment + + diff --git a/src/test/resources/pyyaml/spec-06-03.canonical b/src/test/resources/pyyaml/spec-06-03.canonical new file mode 100644 index 00000000..ec269022 --- /dev/null +++ b/src/test/resources/pyyaml/spec-06-03.canonical @@ -0,0 +1,6 @@ +%YAML 1.1 +--- +!!map { + ? !!str "key" + : !!str "value" +} diff --git a/src/test/resources/pyyaml/spec-06-03.data b/src/test/resources/pyyaml/spec-06-03.data new file mode 100644 index 00000000..9db09129 --- /dev/null +++ b/src/test/resources/pyyaml/spec-06-03.data @@ -0,0 +1,2 @@ +key: # Comment + value diff --git a/src/test/resources/pyyaml/spec-06-04.canonical b/src/test/resources/pyyaml/spec-06-04.canonical new file mode 100644 index 00000000..ec269022 --- /dev/null +++ b/src/test/resources/pyyaml/spec-06-04.canonical @@ -0,0 +1,6 @@ +%YAML 1.1 +--- +!!map { + ? !!str "key" + : !!str "value" +} diff --git a/src/test/resources/pyyaml/spec-06-04.data b/src/test/resources/pyyaml/spec-06-04.data new file mode 100644 index 00000000..86308dd3 --- /dev/null +++ b/src/test/resources/pyyaml/spec-06-04.data @@ -0,0 +1,4 @@ +key: # Comment + # lines + value + diff --git a/src/test/resources/pyyaml/spec-06-05.canonical b/src/test/resources/pyyaml/spec-06-05.canonical new file mode 100644 index 00000000..8da431d0 --- /dev/null +++ b/src/test/resources/pyyaml/spec-06-05.canonical @@ -0,0 +1,16 @@ +%YAML 1.1 +--- +!!map { + ? !!map { + ? !!str "first" + : !!str "Sammy", + ? !!str "last" + : !!str "Sosa" + } + : !!map { + ? !!str "hr" + : !!int "65", + ? !!str "avg" + : !!float "0.278" + } +} diff --git a/src/test/resources/pyyaml/spec-06-05.data b/src/test/resources/pyyaml/spec-06-05.data new file mode 100644 index 00000000..37613f5b --- /dev/null +++ b/src/test/resources/pyyaml/spec-06-05.data @@ -0,0 +1,6 @@ +{ first: Sammy, last: Sosa }: +# Statistics: + hr: # Home runs + 65 + avg: # Average + 0.278 diff --git a/src/test/resources/pyyaml/spec-06-06.canonical b/src/test/resources/pyyaml/spec-06-06.canonical new file mode 100644 index 00000000..513d07a1 --- /dev/null +++ b/src/test/resources/pyyaml/spec-06-06.canonical @@ -0,0 +1,10 @@ +%YAML 1.1 +--- +!!map { + ? !!str "plain" + : !!str "text lines", + ? !!str "quoted" + : !!str "text lines", + ? !!str "block" + : !!str "text\n lines\n" +} diff --git a/src/test/resources/pyyaml/spec-06-06.data b/src/test/resources/pyyaml/spec-06-06.data new file mode 100644 index 00000000..2f62d082 --- /dev/null +++ b/src/test/resources/pyyaml/spec-06-06.data @@ -0,0 +1,7 @@ +plain: text + lines +quoted: "text + lines" +block: | + text + lines diff --git a/src/test/resources/pyyaml/spec-06-07.canonical b/src/test/resources/pyyaml/spec-06-07.canonical new file mode 100644 index 00000000..11357e45 --- /dev/null +++ b/src/test/resources/pyyaml/spec-06-07.canonical @@ -0,0 +1,6 @@ +%YAML 1.1 +--- +!!seq [ + !!str "foo\nbar", + !!str "foo\n\nbar" +] diff --git a/src/test/resources/pyyaml/spec-06-07.data b/src/test/resources/pyyaml/spec-06-07.data new file mode 100644 index 00000000..130cfa74 --- /dev/null +++ b/src/test/resources/pyyaml/spec-06-07.data @@ -0,0 +1,8 @@ +- foo + + bar +- |- + foo + + bar + diff --git a/src/test/resources/pyyaml/spec-06-08.canonical b/src/test/resources/pyyaml/spec-06-08.canonical new file mode 100644 index 00000000..cc72bc84 --- /dev/null +++ b/src/test/resources/pyyaml/spec-06-08.canonical @@ -0,0 +1,5 @@ +%YAML 1.1 +--- !!str +"specific\L\ + trimmed\n\n\n\ + as space" diff --git a/src/test/resources/pyyaml/spec-06-08.data b/src/test/resources/pyyaml/spec-06-08.data new file mode 100644 index 00000000..f2896edb --- /dev/null +++ b/src/test/resources/pyyaml/spec-06-08.data @@ -0,0 +1,2 @@ +>- + specific
trimmed
as
space diff --git a/src/test/resources/pyyaml/spec-07-01.canonical b/src/test/resources/pyyaml/spec-07-01.canonical new file mode 100644 index 00000000..8c8c48db --- /dev/null +++ b/src/test/resources/pyyaml/spec-07-01.canonical @@ -0,0 +1,3 @@ +%YAML 1.1 +--- !!str +"foo" diff --git a/src/test/resources/pyyaml/spec-07-01.data b/src/test/resources/pyyaml/spec-07-01.data new file mode 100644 index 00000000..2113eb61 --- /dev/null +++ b/src/test/resources/pyyaml/spec-07-01.data @@ -0,0 +1,3 @@ +%FOO bar baz # Should be ignored + # with a warning. +--- "foo" diff --git a/src/test/resources/pyyaml/spec-07-02.canonical b/src/test/resources/pyyaml/spec-07-02.canonical new file mode 100644 index 00000000..cb7dd1c3 --- /dev/null +++ b/src/test/resources/pyyaml/spec-07-02.canonical @@ -0,0 +1,3 @@ +%YAML 1.1 +--- +!!str "foo" diff --git a/src/test/resources/pyyaml/spec-07-02.data b/src/test/resources/pyyaml/spec-07-02.data new file mode 100644 index 00000000..c8b73229 --- /dev/null +++ b/src/test/resources/pyyaml/spec-07-02.data @@ -0,0 +1,4 @@ +%YAML 1.2 # Attempt parsing + # with a warning +--- +"foo" diff --git a/src/test/resources/pyyaml/spec-07-03.data b/src/test/resources/pyyaml/spec-07-03.data new file mode 100644 index 00000000..4bfa07ac --- /dev/null +++ b/src/test/resources/pyyaml/spec-07-03.data @@ -0,0 +1,3 @@ +%YAML 1.1 +%YAML 1.1 +foo diff --git a/src/test/resources/pyyaml/spec-07-04.canonical b/src/test/resources/pyyaml/spec-07-04.canonical new file mode 100644 index 00000000..cb7dd1c3 --- /dev/null +++ b/src/test/resources/pyyaml/spec-07-04.canonical @@ -0,0 +1,3 @@ +%YAML 1.1 +--- +!!str "foo" diff --git a/src/test/resources/pyyaml/spec-07-04.data b/src/test/resources/pyyaml/spec-07-04.data new file mode 100644 index 00000000..50f5ab93 --- /dev/null +++ b/src/test/resources/pyyaml/spec-07-04.data @@ -0,0 +1,3 @@ +%TAG !yaml! tag:yaml.org,2002: +--- +!yaml!str "foo" diff --git a/src/test/resources/pyyaml/spec-07-05.data b/src/test/resources/pyyaml/spec-07-05.data new file mode 100644 index 00000000..7276eae9 --- /dev/null +++ b/src/test/resources/pyyaml/spec-07-05.data @@ -0,0 +1,3 @@ +%TAG ! !foo +%TAG ! !foo +bar diff --git a/src/test/resources/pyyaml/spec-07-06.canonical b/src/test/resources/pyyaml/spec-07-06.canonical new file mode 100644 index 00000000..bddf6168 --- /dev/null +++ b/src/test/resources/pyyaml/spec-07-06.canonical @@ -0,0 +1,6 @@ +%YAML 1.1 +--- +!!seq [ + !<!foobar> "baz", + !<tag:yaml.org,2002:str> "string" +] diff --git a/src/test/resources/pyyaml/spec-07-06.data b/src/test/resources/pyyaml/spec-07-06.data new file mode 100644 index 00000000..d9854cbd --- /dev/null +++ b/src/test/resources/pyyaml/spec-07-06.data @@ -0,0 +1,5 @@ +%TAG ! !foo +%TAG !yaml! tag:yaml.org,2002: +--- +- !bar "baz" +- !yaml!str "string" diff --git a/src/test/resources/pyyaml/spec-07-07a.canonical b/src/test/resources/pyyaml/spec-07-07a.canonical new file mode 100644 index 00000000..fa086df9 --- /dev/null +++ b/src/test/resources/pyyaml/spec-07-07a.canonical @@ -0,0 +1,3 @@ +%YAML 1.1 +--- +!<!foo> "bar" diff --git a/src/test/resources/pyyaml/spec-07-07a.data b/src/test/resources/pyyaml/spec-07-07a.data new file mode 100644 index 00000000..9d42ec3d --- /dev/null +++ b/src/test/resources/pyyaml/spec-07-07a.data @@ -0,0 +1,2 @@ +# Private application: +!foo "bar" diff --git a/src/test/resources/pyyaml/spec-07-07b.canonical b/src/test/resources/pyyaml/spec-07-07b.canonical new file mode 100644 index 00000000..fe917d84 --- /dev/null +++ b/src/test/resources/pyyaml/spec-07-07b.canonical @@ -0,0 +1,3 @@ +%YAML 1.1 +--- +!<tag:ben-kiki.org,2000:app/foo> "bar" diff --git a/src/test/resources/pyyaml/spec-07-07b.data b/src/test/resources/pyyaml/spec-07-07b.data new file mode 100644 index 00000000..2d36d0e0 --- /dev/null +++ b/src/test/resources/pyyaml/spec-07-07b.data @@ -0,0 +1,4 @@ +# Migrated to global: +%TAG ! tag:ben-kiki.org,2000:app/ +--- +!foo "bar" diff --git a/src/test/resources/pyyaml/spec-07-08.canonical b/src/test/resources/pyyaml/spec-07-08.canonical new file mode 100644 index 00000000..703aa7b4 --- /dev/null +++ b/src/test/resources/pyyaml/spec-07-08.canonical @@ -0,0 +1,7 @@ +%YAML 1.1 +--- +!!seq [ + !<!foo> "bar", + !<tag:yaml.org,2002:str> "string", + !<tag:ben-kiki.org,2000:type> "baz" +] diff --git a/src/test/resources/pyyaml/spec-07-08.data b/src/test/resources/pyyaml/spec-07-08.data new file mode 100644 index 00000000..e2c6d9e1 --- /dev/null +++ b/src/test/resources/pyyaml/spec-07-08.data @@ -0,0 +1,9 @@ +# Explicitly specify default settings: +%TAG ! ! +%TAG !! tag:yaml.org,2002: +# Named handles have no default: +%TAG !o! tag:ben-kiki.org,2000: +--- +- !foo "bar" +- !!str "string" +- !o!type "baz" diff --git a/src/test/resources/pyyaml/spec-07-09.canonical b/src/test/resources/pyyaml/spec-07-09.canonical new file mode 100644 index 00000000..32d9e943 --- /dev/null +++ b/src/test/resources/pyyaml/spec-07-09.canonical @@ -0,0 +1,9 @@ +%YAML 1.1 +--- +!!str "foo" +%YAML 1.1 +--- +!!str "bar" +%YAML 1.1 +--- +!!str "baz" diff --git a/src/test/resources/pyyaml/spec-07-09.data b/src/test/resources/pyyaml/spec-07-09.data new file mode 100644 index 00000000..1209d47b --- /dev/null +++ b/src/test/resources/pyyaml/spec-07-09.data @@ -0,0 +1,11 @@ +--- +foo +... +# Repeated end marker. +... +--- +bar +# No end marker. +--- +baz +... diff --git a/src/test/resources/pyyaml/spec-07-10.canonical b/src/test/resources/pyyaml/spec-07-10.canonical new file mode 100644 index 00000000..1db650a8 --- /dev/null +++ b/src/test/resources/pyyaml/spec-07-10.canonical @@ -0,0 +1,15 @@ +%YAML 1.1 +--- +!!str "Root flow scalar" +%YAML 1.1 +--- +!!str "Root block scalar\n" +%YAML 1.1 +--- +!!map { + ? !!str "foo" + : !!str "bar" +} +--- +#!!str "" +!!null "" diff --git a/src/test/resources/pyyaml/spec-07-10.data b/src/test/resources/pyyaml/spec-07-10.data new file mode 100644 index 00000000..6939b392 --- /dev/null +++ b/src/test/resources/pyyaml/spec-07-10.data @@ -0,0 +1,11 @@ +"Root flow + scalar" +--- !!str > + Root block + scalar +--- +# Root collection: +foo : bar +... # Is optional. +--- +# Explicit document may be empty. diff --git a/src/test/resources/pyyaml/spec-07-11.data b/src/test/resources/pyyaml/spec-07-11.data new file mode 100644 index 00000000..d11302da --- /dev/null +++ b/src/test/resources/pyyaml/spec-07-11.data @@ -0,0 +1,2 @@ +# A stream may contain +# no documents. diff --git a/src/test/resources/pyyaml/spec-07-12a.canonical b/src/test/resources/pyyaml/spec-07-12a.canonical new file mode 100644 index 00000000..efc116f1 --- /dev/null +++ b/src/test/resources/pyyaml/spec-07-12a.canonical @@ -0,0 +1,6 @@ +%YAML 1.1 +--- +!!map { + ? !!str "foo" + : !!str "bar" +} diff --git a/src/test/resources/pyyaml/spec-07-12a.data b/src/test/resources/pyyaml/spec-07-12a.data new file mode 100644 index 00000000..3807d57d --- /dev/null +++ b/src/test/resources/pyyaml/spec-07-12a.data @@ -0,0 +1,3 @@ +# Implicit document. Root +# collection (mapping) node. +foo : bar diff --git a/src/test/resources/pyyaml/spec-07-12b.canonical b/src/test/resources/pyyaml/spec-07-12b.canonical new file mode 100644 index 00000000..04bcffc8 --- /dev/null +++ b/src/test/resources/pyyaml/spec-07-12b.canonical @@ -0,0 +1,3 @@ +%YAML 1.1 +--- +!!str "Text content\n" diff --git a/src/test/resources/pyyaml/spec-07-12b.data b/src/test/resources/pyyaml/spec-07-12b.data new file mode 100644 index 00000000..43250db3 --- /dev/null +++ b/src/test/resources/pyyaml/spec-07-12b.data @@ -0,0 +1,4 @@ +# Explicit document. Root +# scalar (literal) node. +--- | + Text content diff --git a/src/test/resources/pyyaml/spec-07-13.canonical b/src/test/resources/pyyaml/spec-07-13.canonical new file mode 100644 index 00000000..5af71e91 --- /dev/null +++ b/src/test/resources/pyyaml/spec-07-13.canonical @@ -0,0 +1,9 @@ +%YAML 1.1 +--- +!!str "First document" +--- +!<!foo> "No directives" +--- +!<!foobar> "With directives" +--- +!<!baz> "Reset settings" diff --git a/src/test/resources/pyyaml/spec-07-13.data b/src/test/resources/pyyaml/spec-07-13.data new file mode 100644 index 00000000..ba7ec63e --- /dev/null +++ b/src/test/resources/pyyaml/spec-07-13.data @@ -0,0 +1,9 @@ +! "First document" +--- +!foo "No directives" +%TAG ! !foo +--- +!bar "With directives" +%YAML 1.1 +--- +!baz "Reset settings" diff --git a/src/test/resources/pyyaml/spec-08-01.canonical b/src/test/resources/pyyaml/spec-08-01.canonical new file mode 100644 index 00000000..69e4161b --- /dev/null +++ b/src/test/resources/pyyaml/spec-08-01.canonical @@ -0,0 +1,8 @@ +%YAML 1.1 +--- +!!map { + ? &A1 !!str "foo" + : !!str "bar", + ? &A2 !!str "baz" + : *A1 +} diff --git a/src/test/resources/pyyaml/spec-08-01.data b/src/test/resources/pyyaml/spec-08-01.data new file mode 100644 index 00000000..48986ecb --- /dev/null +++ b/src/test/resources/pyyaml/spec-08-01.data @@ -0,0 +1,2 @@ +!!str &a1 "foo" : !!str bar +&a2 baz : *a1 diff --git a/src/test/resources/pyyaml/spec-08-02.canonical b/src/test/resources/pyyaml/spec-08-02.canonical new file mode 100644 index 00000000..dd6f76ec --- /dev/null +++ b/src/test/resources/pyyaml/spec-08-02.canonical @@ -0,0 +1,8 @@ +%YAML 1.1 +--- +!!map { + ? !!str "First occurrence" + : &A !!str "Value", + ? !!str "Second occurrence" + : *A +} diff --git a/src/test/resources/pyyaml/spec-08-02.data b/src/test/resources/pyyaml/spec-08-02.data new file mode 100644 index 00000000..600d1792 --- /dev/null +++ b/src/test/resources/pyyaml/spec-08-02.data @@ -0,0 +1,2 @@ +First occurrence: &anchor Value +Second occurrence: *anchor diff --git a/src/test/resources/pyyaml/spec-08-03.canonical b/src/test/resources/pyyaml/spec-08-03.canonical new file mode 100644 index 00000000..be7ea8f3 --- /dev/null +++ b/src/test/resources/pyyaml/spec-08-03.canonical @@ -0,0 +1,6 @@ +%YAML 1.1 +--- +!!map { + ? !<tag:yaml.org,2002:str> "foo" + : !<!bar> "baz" +} diff --git a/src/test/resources/pyyaml/spec-08-03.data b/src/test/resources/pyyaml/spec-08-03.data new file mode 100644 index 00000000..8e51f52a --- /dev/null +++ b/src/test/resources/pyyaml/spec-08-03.data @@ -0,0 +1,2 @@ +!<tag:yaml.org,2002:str> foo : + !<!bar> baz diff --git a/src/test/resources/pyyaml/spec-08-04.data b/src/test/resources/pyyaml/spec-08-04.data new file mode 100644 index 00000000..f7d1b01e --- /dev/null +++ b/src/test/resources/pyyaml/spec-08-04.data @@ -0,0 +1,2 @@ +- !<!> foo +- !<$:?> bar diff --git a/src/test/resources/pyyaml/spec-08-05.canonical b/src/test/resources/pyyaml/spec-08-05.canonical new file mode 100644 index 00000000..a5c710ae --- /dev/null +++ b/src/test/resources/pyyaml/spec-08-05.canonical @@ -0,0 +1,7 @@ +%YAML 1.1 +--- +!!seq [ + !<!local> "foo", + !<tag:yaml.org,2002:str> "bar", + !<tag:ben-kiki.org,2000:type> "baz", +] diff --git a/src/test/resources/pyyaml/spec-08-05.data b/src/test/resources/pyyaml/spec-08-05.data new file mode 100644 index 00000000..93576ed7 --- /dev/null +++ b/src/test/resources/pyyaml/spec-08-05.data @@ -0,0 +1,5 @@ +%TAG !o! tag:ben-kiki.org,2000: +--- +- !local foo +- !!str bar +- !o!type baz diff --git a/src/test/resources/pyyaml/spec-08-06.data b/src/test/resources/pyyaml/spec-08-06.data new file mode 100644 index 00000000..85800105 --- /dev/null +++ b/src/test/resources/pyyaml/spec-08-06.data @@ -0,0 +1,5 @@ +%TAG !o! tag:ben-kiki.org,2000: +--- +- !$a!b foo +- !o! bar +- !h!type baz diff --git a/src/test/resources/pyyaml/spec-08-07.canonical b/src/test/resources/pyyaml/spec-08-07.canonical new file mode 100644 index 00000000..e2f43d97 --- /dev/null +++ b/src/test/resources/pyyaml/spec-08-07.canonical @@ -0,0 +1,8 @@ +%YAML 1.1 +--- +!!seq [ + !<tag:yaml.org,2002:str> "12", + !<tag:yaml.org,2002:int> "12", +# !<tag:yaml.org,2002:str> "12", + !<tag:yaml.org,2002:int> "12", +] diff --git a/src/test/resources/pyyaml/spec-08-07.data b/src/test/resources/pyyaml/spec-08-07.data new file mode 100644 index 00000000..98aa565e --- /dev/null +++ b/src/test/resources/pyyaml/spec-08-07.data @@ -0,0 +1,4 @@ +# Assuming conventional resolution: +- "12" +- 12 +- ! 12 diff --git a/src/test/resources/pyyaml/spec-08-08.canonical b/src/test/resources/pyyaml/spec-08-08.canonical new file mode 100644 index 00000000..d3f8b1a7 --- /dev/null +++ b/src/test/resources/pyyaml/spec-08-08.canonical @@ -0,0 +1,15 @@ +%YAML 1.1 +--- +!!map { + ? !!str "foo" + : !!str "bar baz" +} +%YAML 1.1 +--- +!!str "foo bar" +%YAML 1.1 +--- +!!str "foo bar" +%YAML 1.1 +--- +!!str "foo\n" diff --git a/src/test/resources/pyyaml/spec-08-08.data b/src/test/resources/pyyaml/spec-08-08.data new file mode 100644 index 00000000..757a93dd --- /dev/null +++ b/src/test/resources/pyyaml/spec-08-08.data @@ -0,0 +1,13 @@ +--- +foo: + "bar + baz" +--- +"foo + bar" +--- +foo + bar +--- | + foo +... diff --git a/src/test/resources/pyyaml/spec-08-09.canonical b/src/test/resources/pyyaml/spec-08-09.canonical new file mode 100644 index 00000000..3805daf0 --- /dev/null +++ b/src/test/resources/pyyaml/spec-08-09.canonical @@ -0,0 +1,21 @@ +%YAML 1.1 +--- !!map { + ? !!str "scalars" : !!map { + ? !!str "plain" + : !!str "some text", + ? !!str "quoted" + : !!map { + ? !!str "single" + : !!str "some text", + ? !!str "double" + : !!str "some text" + } }, + ? !!str "collections" : !!map { + ? !!str "sequence" : !!seq [ + !!str "entry", + !!map { + ? !!str "key" : !!str "value" + } ], + ? !!str "mapping" : !!map { + ? !!str "key" : !!str "value" +} } } diff --git a/src/test/resources/pyyaml/spec-08-09.data b/src/test/resources/pyyaml/spec-08-09.data new file mode 100644 index 00000000..69da0422 --- /dev/null +++ b/src/test/resources/pyyaml/spec-08-09.data @@ -0,0 +1,11 @@ +--- +scalars: + plain: !!str some text + quoted: + single: 'some text' + double: "some text" +collections: + sequence: !!seq [ !!str entry, + # Mapping entry: + key: value ] + mapping: { key: value } diff --git a/src/test/resources/pyyaml/spec-08-10.canonical b/src/test/resources/pyyaml/spec-08-10.canonical new file mode 100644 index 00000000..8281c5ef --- /dev/null +++ b/src/test/resources/pyyaml/spec-08-10.canonical @@ -0,0 +1,23 @@ +%YAML 1.1 +--- +!!map { + ? !!str "block styles" : !!map { + ? !!str "scalars" : !!map { + ? !!str "literal" + : !!str "#!/usr/bin/perl\n\ + print \"Hello, + world!\\n\";\n", + ? !!str "folded" + : !!str "This sentence + is false.\n" + }, + ? !!str "collections" : !!map { + ? !!str "sequence" : !!seq [ + !!str "entry", + !!map { + ? !!str "key" : !!str "value" + } + ], + ? !!str "mapping" : !!map { + ? !!str "key" : !!str "value" +} } } } diff --git a/src/test/resources/pyyaml/spec-08-10.data b/src/test/resources/pyyaml/spec-08-10.data new file mode 100644 index 00000000..72acc56b --- /dev/null +++ b/src/test/resources/pyyaml/spec-08-10.data @@ -0,0 +1,15 @@ +block styles: + scalars: + literal: !!str | + #!/usr/bin/perl + print "Hello, world!\n"; + folded: > + This sentence + is false. + collections: !!map + sequence: !!seq # Entry: + - entry # Plain + # Mapping entry: + - key: value + mapping: + key: value diff --git a/src/test/resources/pyyaml/spec-08-11.canonical b/src/test/resources/pyyaml/spec-08-11.canonical new file mode 100644 index 00000000..dd6f76ec --- /dev/null +++ b/src/test/resources/pyyaml/spec-08-11.canonical @@ -0,0 +1,8 @@ +%YAML 1.1 +--- +!!map { + ? !!str "First occurrence" + : &A !!str "Value", + ? !!str "Second occurrence" + : *A +} diff --git a/src/test/resources/pyyaml/spec-08-11.data b/src/test/resources/pyyaml/spec-08-11.data new file mode 100644 index 00000000..600d1792 --- /dev/null +++ b/src/test/resources/pyyaml/spec-08-11.data @@ -0,0 +1,2 @@ +First occurrence: &anchor Value +Second occurrence: *anchor diff --git a/src/test/resources/pyyaml/spec-08-12.canonical b/src/test/resources/pyyaml/spec-08-12.canonical new file mode 100644 index 00000000..93899f4e --- /dev/null +++ b/src/test/resources/pyyaml/spec-08-12.canonical @@ -0,0 +1,10 @@ +%YAML 1.1 +--- +!!seq [ + !!str "Without properties", + &A !!str "Anchored", + !!str "Tagged", + *A, + !!str "", + !!str "", +] diff --git a/src/test/resources/pyyaml/spec-08-12.data b/src/test/resources/pyyaml/spec-08-12.data new file mode 100644 index 00000000..3d4c6b7c --- /dev/null +++ b/src/test/resources/pyyaml/spec-08-12.data @@ -0,0 +1,8 @@ +[ + Without properties, + &anchor "Anchored", + !!str 'Tagged', + *anchor, # Alias node + !!str , # Empty plain scalar + '', # Empty plain scalar +] diff --git a/src/test/resources/pyyaml/spec-08-13.canonical b/src/test/resources/pyyaml/spec-08-13.canonical new file mode 100644 index 00000000..618bb7bd --- /dev/null +++ b/src/test/resources/pyyaml/spec-08-13.canonical @@ -0,0 +1,10 @@ +%YAML 1.1 +--- +!!map { + ? !!str "foo" +# : !!str "", +# ? !!str "" + : !!null "", + ? !!null "" + : !!str "bar", +} diff --git a/src/test/resources/pyyaml/spec-08-13.data b/src/test/resources/pyyaml/spec-08-13.data new file mode 100644 index 00000000..ebe663ac --- /dev/null +++ b/src/test/resources/pyyaml/spec-08-13.data @@ -0,0 +1,4 @@ +{ + ? foo :, + ? : bar, +} diff --git a/src/test/resources/pyyaml/spec-08-14.canonical b/src/test/resources/pyyaml/spec-08-14.canonical new file mode 100644 index 00000000..11db439f --- /dev/null +++ b/src/test/resources/pyyaml/spec-08-14.canonical @@ -0,0 +1,10 @@ +%YAML 1.1 +--- +!!seq [ + !!str "flow in block", + !!str "Block scalar\n", + !!map { + ? !!str "foo" + : !!str "bar" + } +] diff --git a/src/test/resources/pyyaml/spec-08-14.data b/src/test/resources/pyyaml/spec-08-14.data new file mode 100644 index 00000000..2fbb1f70 --- /dev/null +++ b/src/test/resources/pyyaml/spec-08-14.data @@ -0,0 +1,5 @@ +- "flow in block" +- > + Block scalar +- !!map # Block collection + foo : bar diff --git a/src/test/resources/pyyaml/spec-08-15.canonical b/src/test/resources/pyyaml/spec-08-15.canonical new file mode 100644 index 00000000..76f028e6 --- /dev/null +++ b/src/test/resources/pyyaml/spec-08-15.canonical @@ -0,0 +1,11 @@ +%YAML 1.1 +--- +!!seq [ + !!null "", + !!map { + ? !!str "foo" + : !!null "", + ? !!null "" + : !!str "bar", + } +] diff --git a/src/test/resources/pyyaml/spec-08-15.data b/src/test/resources/pyyaml/spec-08-15.data new file mode 100644 index 00000000..7c86bcf3 --- /dev/null +++ b/src/test/resources/pyyaml/spec-08-15.data @@ -0,0 +1,5 @@ +- # Empty plain scalar +- ? foo + : + ? + : bar diff --git a/src/test/resources/pyyaml/spec-09-01.canonical b/src/test/resources/pyyaml/spec-09-01.canonical new file mode 100644 index 00000000..e71a5484 --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-01.canonical @@ -0,0 +1,11 @@ +%YAML 1.1 +--- +!!map { + ? !!str "simple key" + : !!map { + ? !!str "also simple" + : !!str "value", + ? !!str "not a simple key" + : !!str "any value" + } +} diff --git a/src/test/resources/pyyaml/spec-09-01.data b/src/test/resources/pyyaml/spec-09-01.data new file mode 100644 index 00000000..9e83eaff --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-01.data @@ -0,0 +1,6 @@ +"simple key" : { + "also simple" : value, + ? "not a + simple key" : "any + value" +} diff --git a/src/test/resources/pyyaml/spec-09-02.canonical b/src/test/resources/pyyaml/spec-09-02.canonical new file mode 100644 index 00000000..6f8f41ad --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-02.canonical @@ -0,0 +1,7 @@ +%YAML 1.1 +--- +!!str "as space \ + trimmed\n\ + specific\L\n\ + escaped\t\n\ + none" diff --git a/src/test/resources/pyyaml/spec-09-02.data b/src/test/resources/pyyaml/spec-09-02.data new file mode 100644 index 00000000..d84883dc --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-02.data @@ -0,0 +1,6 @@ + "as space + trimmed + + specific
+ escaped \
+ none" diff --git a/src/test/resources/pyyaml/spec-09-03.canonical b/src/test/resources/pyyaml/spec-09-03.canonical new file mode 100644 index 00000000..658c6df8 --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-03.canonical @@ -0,0 +1,7 @@ +%YAML 1.1 +--- +!!seq [ + !!str " last", + !!str " last", + !!str " \tfirst last", +] diff --git a/src/test/resources/pyyaml/spec-09-03.data b/src/test/resources/pyyaml/spec-09-03.data new file mode 100644 index 00000000..e0b914d7 --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-03.data @@ -0,0 +1,6 @@ +- " + last" +- " + last" +- " first + last" diff --git a/src/test/resources/pyyaml/spec-09-04.canonical b/src/test/resources/pyyaml/spec-09-04.canonical new file mode 100644 index 00000000..fa466324 --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-04.canonical @@ -0,0 +1,6 @@ +%YAML 1.1 +--- +!!str "first \ + inner 1 \ + inner 2 \ + last" diff --git a/src/test/resources/pyyaml/spec-09-04.data b/src/test/resources/pyyaml/spec-09-04.data new file mode 100644 index 00000000..313a91b4 --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-04.data @@ -0,0 +1,4 @@ + "first + inner 1 + \ inner 2 \ + last" diff --git a/src/test/resources/pyyaml/spec-09-05.canonical b/src/test/resources/pyyaml/spec-09-05.canonical new file mode 100644 index 00000000..24d10528 --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-05.canonical @@ -0,0 +1,7 @@ +%YAML 1.1 +--- +!!seq [ + !!str "first ", + !!str "first\nlast", + !!str "first inner \tlast", +] diff --git a/src/test/resources/pyyaml/spec-09-05.data b/src/test/resources/pyyaml/spec-09-05.data new file mode 100644 index 00000000..624c30ea --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-05.data @@ -0,0 +1,8 @@ +- "first + " +- "first + + last" +- "first + inner + \ last" diff --git a/src/test/resources/pyyaml/spec-09-06.canonical b/src/test/resources/pyyaml/spec-09-06.canonical new file mode 100644 index 00000000..50287722 --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-06.canonical @@ -0,0 +1,3 @@ +%YAML 1.1 +--- +!!str "here's to \"quotes\"" diff --git a/src/test/resources/pyyaml/spec-09-06.data b/src/test/resources/pyyaml/spec-09-06.data new file mode 100644 index 00000000..b038078e --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-06.data @@ -0,0 +1 @@ + 'here''s to "quotes"' diff --git a/src/test/resources/pyyaml/spec-09-07.canonical b/src/test/resources/pyyaml/spec-09-07.canonical new file mode 100644 index 00000000..e71a5484 --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-07.canonical @@ -0,0 +1,11 @@ +%YAML 1.1 +--- +!!map { + ? !!str "simple key" + : !!map { + ? !!str "also simple" + : !!str "value", + ? !!str "not a simple key" + : !!str "any value" + } +} diff --git a/src/test/resources/pyyaml/spec-09-07.data b/src/test/resources/pyyaml/spec-09-07.data new file mode 100644 index 00000000..755b54a0 --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-07.data @@ -0,0 +1,6 @@ +'simple key' : { + 'also simple' : value, + ? 'not a + simple key' : 'any + value' +} diff --git a/src/test/resources/pyyaml/spec-09-08.canonical b/src/test/resources/pyyaml/spec-09-08.canonical new file mode 100644 index 00000000..06abdb5f --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-08.canonical @@ -0,0 +1,6 @@ +%YAML 1.1 +--- +!!str "as space \ + trimmed\n\ + specific\L\n\ + none" diff --git a/src/test/resources/pyyaml/spec-09-08.data b/src/test/resources/pyyaml/spec-09-08.data new file mode 100644 index 00000000..aa4d4589 --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-08.data @@ -0,0 +1 @@ + 'as space
trimmed
specific
none' diff --git a/src/test/resources/pyyaml/spec-09-09.canonical b/src/test/resources/pyyaml/spec-09-09.canonical new file mode 100644 index 00000000..658c6df8 --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-09.canonical @@ -0,0 +1,7 @@ +%YAML 1.1 +--- +!!seq [ + !!str " last", + !!str " last", + !!str " \tfirst last", +] diff --git a/src/test/resources/pyyaml/spec-09-09.data b/src/test/resources/pyyaml/spec-09-09.data new file mode 100644 index 00000000..52171df3 --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-09.data @@ -0,0 +1,6 @@ +- ' + last' +- ' + last' +- ' first + last' diff --git a/src/test/resources/pyyaml/spec-09-10.canonical b/src/test/resources/pyyaml/spec-09-10.canonical new file mode 100644 index 00000000..2028d044 --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-10.canonical @@ -0,0 +1,5 @@ +%YAML 1.1 +--- +!!str "first \ + inner \ + last" diff --git a/src/test/resources/pyyaml/spec-09-10.data b/src/test/resources/pyyaml/spec-09-10.data new file mode 100644 index 00000000..0e414495 --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-10.data @@ -0,0 +1,3 @@ + 'first + inner + last' diff --git a/src/test/resources/pyyaml/spec-09-11.canonical b/src/test/resources/pyyaml/spec-09-11.canonical new file mode 100644 index 00000000..4eb222c9 --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-11.canonical @@ -0,0 +1,6 @@ +%YAML 1.1 +--- +!!seq [ + !!str "first ", + !!str "first\nlast", +] diff --git a/src/test/resources/pyyaml/spec-09-11.data b/src/test/resources/pyyaml/spec-09-11.data new file mode 100644 index 00000000..5efa873b --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-11.data @@ -0,0 +1,5 @@ +- 'first + ' +- 'first + + last' diff --git a/src/test/resources/pyyaml/spec-09-12.canonical b/src/test/resources/pyyaml/spec-09-12.canonical new file mode 100644 index 00000000..d8e6dce7 --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-12.canonical @@ -0,0 +1,12 @@ +%YAML 1.1 +--- +!!seq [ + !!str "::std::vector", + !!str "Up, up, and away!", + !!int "-123", + !!seq [ + !!str "::std::vector", + !!str "Up, up, and away!", + !!int "-123", + ] +] diff --git a/src/test/resources/pyyaml/spec-09-12.data b/src/test/resources/pyyaml/spec-09-12.data new file mode 100644 index 00000000..b9a3ac53 --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-12.data @@ -0,0 +1,8 @@ +# Outside flow collection: +- ::std::vector +- Up, up, and away! +- -123 +# Inside flow collection: +- [ '::std::vector', + "Up, up, and away!", + -123 ] diff --git a/src/test/resources/pyyaml/spec-09-13.canonical b/src/test/resources/pyyaml/spec-09-13.canonical new file mode 100644 index 00000000..e71a5484 --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-13.canonical @@ -0,0 +1,11 @@ +%YAML 1.1 +--- +!!map { + ? !!str "simple key" + : !!map { + ? !!str "also simple" + : !!str "value", + ? !!str "not a simple key" + : !!str "any value" + } +} diff --git a/src/test/resources/pyyaml/spec-09-13.data b/src/test/resources/pyyaml/spec-09-13.data new file mode 100644 index 00000000..b156386a --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-13.data @@ -0,0 +1,6 @@ +simple key : { + also simple : value, + ? not a + simple key : any + value +} diff --git a/src/test/resources/pyyaml/spec-09-14.data b/src/test/resources/pyyaml/spec-09-14.data new file mode 100644 index 00000000..97f23162 --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-14.data @@ -0,0 +1,14 @@ +--- +--- ||| : foo +... >>>: bar +--- +[ +--- +, +... , +{ +--- : +... # Nested +} +] +... diff --git a/src/test/resources/pyyaml/spec-09-15.canonical b/src/test/resources/pyyaml/spec-09-15.canonical new file mode 100644 index 00000000..df020407 --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-15.canonical @@ -0,0 +1,18 @@ +%YAML 1.1 +--- +!!map { + ? !!str "---" + : !!str "foo", + ? !!str "..." + : !!str "bar" +} +%YAML 1.1 +--- +!!seq [ + !!str "---", + !!str "...", + !!map { + ? !!str "---" + : !!str "..." + } +] diff --git a/src/test/resources/pyyaml/spec-09-15.data b/src/test/resources/pyyaml/spec-09-15.data new file mode 100644 index 00000000..e6863b04 --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-15.data @@ -0,0 +1,13 @@ +--- +"---" : foo +...: bar +--- +[ +---, +..., +{ +? --- +: ... +} +] +... diff --git a/src/test/resources/pyyaml/spec-09-16.canonical b/src/test/resources/pyyaml/spec-09-16.canonical new file mode 100644 index 00000000..06abdb5f --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-16.canonical @@ -0,0 +1,6 @@ +%YAML 1.1 +--- +!!str "as space \ + trimmed\n\ + specific\L\n\ + none" diff --git a/src/test/resources/pyyaml/spec-09-16.data b/src/test/resources/pyyaml/spec-09-16.data new file mode 100644 index 00000000..473beb9a --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-16.data @@ -0,0 +1,3 @@ +# Tabs are confusing: +# as space/trimmed/specific/none + as space
trimmed
specific
none diff --git a/src/test/resources/pyyaml/spec-09-17.canonical b/src/test/resources/pyyaml/spec-09-17.canonical new file mode 100644 index 00000000..68cb70d1 --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-17.canonical @@ -0,0 +1,4 @@ +%YAML 1.1 +--- +!!str "first line\n\ + more line" diff --git a/src/test/resources/pyyaml/spec-09-17.data b/src/test/resources/pyyaml/spec-09-17.data new file mode 100644 index 00000000..97bc46c4 --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-17.data @@ -0,0 +1,3 @@ + first line + + more line diff --git a/src/test/resources/pyyaml/spec-09-18.canonical b/src/test/resources/pyyaml/spec-09-18.canonical new file mode 100644 index 00000000..f21428f6 --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-18.canonical @@ -0,0 +1,8 @@ +%YAML 1.1 +--- +!!seq [ + !!str "literal\n", + !!str " folded\n", + !!str "keep\n\n", + !!str " strip", +] diff --git a/src/test/resources/pyyaml/spec-09-18.data b/src/test/resources/pyyaml/spec-09-18.data new file mode 100644 index 00000000..68c5d7cc --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-18.data @@ -0,0 +1,9 @@ +- | # Just the style + literal +- >1 # Indentation indicator + folded +- |+ # Chomping indicator + keep + +- >-1 # Both indicators + strip diff --git a/src/test/resources/pyyaml/spec-09-19.canonical b/src/test/resources/pyyaml/spec-09-19.canonical new file mode 100644 index 00000000..3e828d7d --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-19.canonical @@ -0,0 +1,6 @@ +%YAML 1.1 +--- +!!seq [ + !!str "literal\n", + !!str "folded\n", +] diff --git a/src/test/resources/pyyaml/spec-09-19.data b/src/test/resources/pyyaml/spec-09-19.data new file mode 100644 index 00000000..f0e589dc --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-19.data @@ -0,0 +1,4 @@ +- | + literal +- > + folded diff --git a/src/test/resources/pyyaml/spec-09-20.canonical b/src/test/resources/pyyaml/spec-09-20.canonical new file mode 100644 index 00000000..d03bef51 --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-20.canonical @@ -0,0 +1,8 @@ +%YAML 1.1 +--- +!!seq [ + !!str "detected\n", + !!str "\n\n# detected\n", + !!str " explicit\n", + !!str "\t\ndetected\n", +] diff --git a/src/test/resources/pyyaml/spec-09-20.data b/src/test/resources/pyyaml/spec-09-20.data new file mode 100644 index 00000000..39bee044 --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-20.data @@ -0,0 +1,11 @@ +- | + detected +- > + + + # detected +- |1 + explicit +- > + + detected diff --git a/src/test/resources/pyyaml/spec-09-21.data b/src/test/resources/pyyaml/spec-09-21.data new file mode 100644 index 00000000..0fdd14f2 --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-21.data @@ -0,0 +1,8 @@ +- | + + text +- > + text + text +- |1 + text diff --git a/src/test/resources/pyyaml/spec-09-22.canonical b/src/test/resources/pyyaml/spec-09-22.canonical new file mode 100644 index 00000000..c1bbcd22 --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-22.canonical @@ -0,0 +1,10 @@ +%YAML 1.1 +--- +!!map { + ? !!str "strip" + : !!str "text", + ? !!str "clip" + : !!str "text\n", + ? !!str "keep" + : !!str "text\L", +} diff --git a/src/test/resources/pyyaml/spec-09-22.data b/src/test/resources/pyyaml/spec-09-22.data new file mode 100644 index 00000000..0dd51eb3 --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-22.data @@ -0,0 +1,4 @@ +strip: |- + text
clip: | + text
keep: |+ + text
\ No newline at end of file diff --git a/src/test/resources/pyyaml/spec-09-23.canonical b/src/test/resources/pyyaml/spec-09-23.canonical new file mode 100644 index 00000000..c4444caa --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-23.canonical @@ -0,0 +1,10 @@ +%YAML 1.1 +--- +!!map { + ? !!str "strip" + : !!str "# text", + ? !!str "clip" + : !!str "# text\n", + ? !!str "keep" + : !!str "# text\L\n", +} diff --git a/src/test/resources/pyyaml/spec-09-23.data b/src/test/resources/pyyaml/spec-09-23.data new file mode 100644 index 00000000..8972d2b6 --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-23.data @@ -0,0 +1,11 @@ + # Strip + # Comments: +strip: |- + # text
# Clip + # comments: +
clip: | + # text
# Keep + # comments: +
keep: |+ + # text
# Trail + # comments. diff --git a/src/test/resources/pyyaml/spec-09-24.canonical b/src/test/resources/pyyaml/spec-09-24.canonical new file mode 100644 index 00000000..45a99b01 --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-24.canonical @@ -0,0 +1,10 @@ +%YAML 1.1 +--- +!!map { + ? !!str "strip" + : !!str "", + ? !!str "clip" + : !!str "", + ? !!str "keep" + : !!str "\n", +} diff --git a/src/test/resources/pyyaml/spec-09-24.data b/src/test/resources/pyyaml/spec-09-24.data new file mode 100644 index 00000000..de0b64bb --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-24.data @@ -0,0 +1,6 @@ +strip: >- + +clip: > + +keep: |+ + diff --git a/src/test/resources/pyyaml/spec-09-25.canonical b/src/test/resources/pyyaml/spec-09-25.canonical new file mode 100644 index 00000000..9d2327bb --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-25.canonical @@ -0,0 +1,4 @@ +%YAML 1.1 +--- +!!str "literal\n\ + \ttext\n" diff --git a/src/test/resources/pyyaml/spec-09-25.data b/src/test/resources/pyyaml/spec-09-25.data new file mode 100644 index 00000000..f6303a14 --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-25.data @@ -0,0 +1,3 @@ +| # Simple block scalar + literal + text diff --git a/src/test/resources/pyyaml/spec-09-26.canonical b/src/test/resources/pyyaml/spec-09-26.canonical new file mode 100644 index 00000000..3029a116 --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-26.canonical @@ -0,0 +1,3 @@ +%YAML 1.1 +--- +!!str "\n\nliteral\n\ntext\n" diff --git a/src/test/resources/pyyaml/spec-09-26.data b/src/test/resources/pyyaml/spec-09-26.data new file mode 100644 index 00000000..f28555ab --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-26.data @@ -0,0 +1,8 @@ +| + + + literal + + text + + # Comment diff --git a/src/test/resources/pyyaml/spec-09-27.canonical b/src/test/resources/pyyaml/spec-09-27.canonical new file mode 100644 index 00000000..3029a116 --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-27.canonical @@ -0,0 +1,3 @@ +%YAML 1.1 +--- +!!str "\n\nliteral\n\ntext\n" diff --git a/src/test/resources/pyyaml/spec-09-27.data b/src/test/resources/pyyaml/spec-09-27.data new file mode 100644 index 00000000..f28555ab --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-27.data @@ -0,0 +1,8 @@ +| + + + literal + + text + + # Comment diff --git a/src/test/resources/pyyaml/spec-09-28.canonical b/src/test/resources/pyyaml/spec-09-28.canonical new file mode 100644 index 00000000..3029a116 --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-28.canonical @@ -0,0 +1,3 @@ +%YAML 1.1 +--- +!!str "\n\nliteral\n\ntext\n" diff --git a/src/test/resources/pyyaml/spec-09-28.data b/src/test/resources/pyyaml/spec-09-28.data new file mode 100644 index 00000000..f28555ab --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-28.data @@ -0,0 +1,8 @@ +| + + + literal + + text + + # Comment diff --git a/src/test/resources/pyyaml/spec-09-29.canonical b/src/test/resources/pyyaml/spec-09-29.canonical new file mode 100644 index 00000000..0980789a --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-29.canonical @@ -0,0 +1,4 @@ +%YAML 1.1 +--- +!!str "folded text\n\ + \tlines\n" diff --git a/src/test/resources/pyyaml/spec-09-29.data b/src/test/resources/pyyaml/spec-09-29.data new file mode 100644 index 00000000..82e611fc --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-29.data @@ -0,0 +1,4 @@ +> # Simple folded scalar + folded + text + lines diff --git a/src/test/resources/pyyaml/spec-09-30.canonical b/src/test/resources/pyyaml/spec-09-30.canonical new file mode 100644 index 00000000..fc37db1c --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-30.canonical @@ -0,0 +1,7 @@ +%YAML 1.1 +--- +!!str "folded line\n\ + next line\n\n\ + \ * bullet\n\ + \ * list\n\n\ + last line\n" diff --git a/src/test/resources/pyyaml/spec-09-30.data b/src/test/resources/pyyaml/spec-09-30.data new file mode 100644 index 00000000..a4d8c36a --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-30.data @@ -0,0 +1,14 @@ +> + folded + line + + next + line + + * bullet + * list + + last + line + +# Comment diff --git a/src/test/resources/pyyaml/spec-09-31.canonical b/src/test/resources/pyyaml/spec-09-31.canonical new file mode 100644 index 00000000..fc37db1c --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-31.canonical @@ -0,0 +1,7 @@ +%YAML 1.1 +--- +!!str "folded line\n\ + next line\n\n\ + \ * bullet\n\ + \ * list\n\n\ + last line\n" diff --git a/src/test/resources/pyyaml/spec-09-31.data b/src/test/resources/pyyaml/spec-09-31.data new file mode 100644 index 00000000..a4d8c36a --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-31.data @@ -0,0 +1,14 @@ +> + folded + line + + next + line + + * bullet + * list + + last + line + +# Comment diff --git a/src/test/resources/pyyaml/spec-09-32.canonical b/src/test/resources/pyyaml/spec-09-32.canonical new file mode 100644 index 00000000..fc37db1c --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-32.canonical @@ -0,0 +1,7 @@ +%YAML 1.1 +--- +!!str "folded line\n\ + next line\n\n\ + \ * bullet\n\ + \ * list\n\n\ + last line\n" diff --git a/src/test/resources/pyyaml/spec-09-32.data b/src/test/resources/pyyaml/spec-09-32.data new file mode 100644 index 00000000..a4d8c36a --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-32.data @@ -0,0 +1,14 @@ +> + folded + line + + next + line + + * bullet + * list + + last + line + +# Comment diff --git a/src/test/resources/pyyaml/spec-09-33.canonical b/src/test/resources/pyyaml/spec-09-33.canonical new file mode 100644 index 00000000..fc37db1c --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-33.canonical @@ -0,0 +1,7 @@ +%YAML 1.1 +--- +!!str "folded line\n\ + next line\n\n\ + \ * bullet\n\ + \ * list\n\n\ + last line\n" diff --git a/src/test/resources/pyyaml/spec-09-33.data b/src/test/resources/pyyaml/spec-09-33.data new file mode 100644 index 00000000..a4d8c36a --- /dev/null +++ b/src/test/resources/pyyaml/spec-09-33.data @@ -0,0 +1,14 @@ +> + folded + line + + next + line + + * bullet + * list + + last + line + +# Comment diff --git a/src/test/resources/pyyaml/spec-10-01.canonical b/src/test/resources/pyyaml/spec-10-01.canonical new file mode 100644 index 00000000..d08cdd40 --- /dev/null +++ b/src/test/resources/pyyaml/spec-10-01.canonical @@ -0,0 +1,12 @@ +%YAML 1.1 +--- +!!seq [ + !!seq [ + !!str "inner", + !!str "inner", + ], + !!seq [ + !!str "inner", + !!str "last", + ], +] diff --git a/src/test/resources/pyyaml/spec-10-01.data b/src/test/resources/pyyaml/spec-10-01.data new file mode 100644 index 00000000..e668d38d --- /dev/null +++ b/src/test/resources/pyyaml/spec-10-01.data @@ -0,0 +1,2 @@ +- [ inner, inner, ] +- [inner,last] diff --git a/src/test/resources/pyyaml/spec-10-02.canonical b/src/test/resources/pyyaml/spec-10-02.canonical new file mode 100644 index 00000000..82fe0d94 --- /dev/null +++ b/src/test/resources/pyyaml/spec-10-02.canonical @@ -0,0 +1,14 @@ +%YAML 1.1 +--- +!!seq [ + !!str "double quoted", + !!str "single quoted", + !!str "plain text", + !!seq [ + !!str "nested", + ], + !!map { + ? !!str "single" + : !!str "pair" + } +] diff --git a/src/test/resources/pyyaml/spec-10-02.data b/src/test/resources/pyyaml/spec-10-02.data new file mode 100644 index 00000000..3b233515 --- /dev/null +++ b/src/test/resources/pyyaml/spec-10-02.data @@ -0,0 +1,8 @@ +[ +"double + quoted", 'single + quoted', +plain + text, [ nested ], +single: pair , +] diff --git a/src/test/resources/pyyaml/spec-10-03.canonical b/src/test/resources/pyyaml/spec-10-03.canonical new file mode 100644 index 00000000..1443395b --- /dev/null +++ b/src/test/resources/pyyaml/spec-10-03.canonical @@ -0,0 +1,12 @@ +%YAML 1.1 +--- +!!map { + ? !!str "block" + : !!seq [ + !!str "one", + !!map { + ? !!str "two" + : !!str "three" + } + ] +} diff --git a/src/test/resources/pyyaml/spec-10-03.data b/src/test/resources/pyyaml/spec-10-03.data new file mode 100644 index 00000000..9e15f83b --- /dev/null +++ b/src/test/resources/pyyaml/spec-10-03.data @@ -0,0 +1,4 @@ +block: # Block + # sequence +- one +- two : three diff --git a/src/test/resources/pyyaml/spec-10-04.canonical b/src/test/resources/pyyaml/spec-10-04.canonical new file mode 100644 index 00000000..ae486a3c --- /dev/null +++ b/src/test/resources/pyyaml/spec-10-04.canonical @@ -0,0 +1,11 @@ +%YAML 1.1 +--- +!!map { + ? !!str "block" + : !!seq [ + !!str "one", + !!seq [ + !!str "two" + ] + ] +} diff --git a/src/test/resources/pyyaml/spec-10-04.data b/src/test/resources/pyyaml/spec-10-04.data new file mode 100644 index 00000000..2905b0d9 --- /dev/null +++ b/src/test/resources/pyyaml/spec-10-04.data @@ -0,0 +1,4 @@ +block: +- one +- + - two diff --git a/src/test/resources/pyyaml/spec-10-05.canonical b/src/test/resources/pyyaml/spec-10-05.canonical new file mode 100644 index 00000000..07cc0c98 --- /dev/null +++ b/src/test/resources/pyyaml/spec-10-05.canonical @@ -0,0 +1,14 @@ +%YAML 1.1 +--- +!!seq [ + !!null "", + !!str "block node\n", + !!seq [ + !!str "one", + !!str "two", + ], + !!map { + ? !!str "one" + : !!str "two", + } +] diff --git a/src/test/resources/pyyaml/spec-10-05.data b/src/test/resources/pyyaml/spec-10-05.data new file mode 100644 index 00000000..f19a99e3 --- /dev/null +++ b/src/test/resources/pyyaml/spec-10-05.data @@ -0,0 +1,7 @@ +- # Empty +- | + block node +- - one # in-line + - two # sequence +- one: two # in-line + # mapping diff --git a/src/test/resources/pyyaml/spec-10-06.canonical b/src/test/resources/pyyaml/spec-10-06.canonical new file mode 100644 index 00000000..d9986c28 --- /dev/null +++ b/src/test/resources/pyyaml/spec-10-06.canonical @@ -0,0 +1,16 @@ +%YAML 1.1 +--- +!!seq [ + !!map { + ? !!str "inner" + : !!str "entry", + ? !!str "also" + : !!str "inner" + }, + !!map { + ? !!str "inner" + : !!str "entry", + ? !!str "last" + : !!str "entry" + } +] diff --git a/src/test/resources/pyyaml/spec-10-06.data b/src/test/resources/pyyaml/spec-10-06.data new file mode 100644 index 00000000..860ba25b --- /dev/null +++ b/src/test/resources/pyyaml/spec-10-06.data @@ -0,0 +1,2 @@ +- { inner : entry , also: inner , } +- {inner: entry,last : entry} diff --git a/src/test/resources/pyyaml/spec-10-07.canonical b/src/test/resources/pyyaml/spec-10-07.canonical new file mode 100644 index 00000000..ec74230a --- /dev/null +++ b/src/test/resources/pyyaml/spec-10-07.canonical @@ -0,0 +1,16 @@ +%YAML 1.1 +--- +!!map { + ? !!null "" + : !!str "value", + ? !!str "explicit key" + : !!str "value", + ? !!str "simple key" + : !!str "value", + ? !!seq [ + !!str "collection", + !!str "simple", + !!str "key" + ] + : !!str "value" +} diff --git a/src/test/resources/pyyaml/spec-10-07.data b/src/test/resources/pyyaml/spec-10-07.data new file mode 100644 index 00000000..ff943fbc --- /dev/null +++ b/src/test/resources/pyyaml/spec-10-07.data @@ -0,0 +1,7 @@ +{ +? : value, # Empty key +? explicit + key: value, +simple key : value, +[ collection, simple, key ]: value +} diff --git a/src/test/resources/pyyaml/spec-10-08.data b/src/test/resources/pyyaml/spec-10-08.data new file mode 100644 index 00000000..55bd788a --- /dev/null +++ b/src/test/resources/pyyaml/spec-10-08.data @@ -0,0 +1,5 @@ +{ +multi-line + simple key : value, +very long ...................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................(>1KB)................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................... key: value +} diff --git a/src/test/resources/pyyaml/spec-10-09.canonical b/src/test/resources/pyyaml/spec-10-09.canonical new file mode 100644 index 00000000..4d9827b1 --- /dev/null +++ b/src/test/resources/pyyaml/spec-10-09.canonical @@ -0,0 +1,8 @@ +%YAML 1.1 +--- +!!map { + ? !!str "key" + : !!str "value", + ? !!str "empty" + : !!null "", +} diff --git a/src/test/resources/pyyaml/spec-10-09.data b/src/test/resources/pyyaml/spec-10-09.data new file mode 100644 index 00000000..4d55e21d --- /dev/null +++ b/src/test/resources/pyyaml/spec-10-09.data @@ -0,0 +1,4 @@ +{ +key : value, +empty: # empty value↓ +} diff --git a/src/test/resources/pyyaml/spec-10-10.canonical b/src/test/resources/pyyaml/spec-10-10.canonical new file mode 100644 index 00000000..016fb640 --- /dev/null +++ b/src/test/resources/pyyaml/spec-10-10.canonical @@ -0,0 +1,16 @@ +%YAML 1.1 +--- +!!map { + ? !!str "explicit key1" + : !!str "explicit value", + ? !!str "explicit key2" + : !!null "", + ? !!str "explicit key3" + : !!null "", + ? !!str "simple key1" + : !!str "explicit value", + ? !!str "simple key2" + : !!null "", + ? !!str "simple key3" + : !!null "", +} diff --git a/src/test/resources/pyyaml/spec-10-10.data b/src/test/resources/pyyaml/spec-10-10.data new file mode 100644 index 00000000..0888b054 --- /dev/null +++ b/src/test/resources/pyyaml/spec-10-10.data @@ -0,0 +1,8 @@ +{ +? explicit key1 : explicit value, +? explicit key2 : , # Explicit empty +? explicit key3, # Empty value +simple key1 : explicit value, +simple key2 : , # Explicit empty +simple key3, # Empty value +} diff --git a/src/test/resources/pyyaml/spec-10-11.canonical b/src/test/resources/pyyaml/spec-10-11.canonical new file mode 100644 index 00000000..7309544c --- /dev/null +++ b/src/test/resources/pyyaml/spec-10-11.canonical @@ -0,0 +1,24 @@ +%YAML 1.1 +--- +!!seq [ + !!map { + ? !!str "explicit key1" + : !!str "explicit value", + }, + !!map { + ? !!str "explicit key2" + : !!null "", + }, + !!map { + ? !!str "explicit key3" + : !!null "", + }, + !!map { + ? !!str "simple key1" + : !!str "explicit value", + }, + !!map { + ? !!str "simple key2" + : !!null "", + }, +] diff --git a/src/test/resources/pyyaml/spec-10-11.data b/src/test/resources/pyyaml/spec-10-11.data new file mode 100644 index 00000000..9f055684 --- /dev/null +++ b/src/test/resources/pyyaml/spec-10-11.data @@ -0,0 +1,7 @@ +[ +? explicit key1 : explicit value, +? explicit key2 : , # Explicit empty +? explicit key3, # Implicit empty +simple key1 : explicit value, +simple key2 : , # Explicit empty +] diff --git a/src/test/resources/pyyaml/spec-10-12.canonical b/src/test/resources/pyyaml/spec-10-12.canonical new file mode 100644 index 00000000..a95dd40c --- /dev/null +++ b/src/test/resources/pyyaml/spec-10-12.canonical @@ -0,0 +1,9 @@ +%YAML 1.1 +--- +!!map { + ? !!str "block" + : !!map { + ? !!str "key" + : !!str "value" + } +} diff --git a/src/test/resources/pyyaml/spec-10-12.data b/src/test/resources/pyyaml/spec-10-12.data new file mode 100644 index 00000000..55214435 --- /dev/null +++ b/src/test/resources/pyyaml/spec-10-12.data @@ -0,0 +1,3 @@ +block: # Block + # mapping + key: value diff --git a/src/test/resources/pyyaml/spec-10-13.canonical b/src/test/resources/pyyaml/spec-10-13.canonical new file mode 100644 index 00000000..e183c50f --- /dev/null +++ b/src/test/resources/pyyaml/spec-10-13.canonical @@ -0,0 +1,11 @@ +%YAML 1.1 +--- +!!map { + ? !!str "explicit key" + : !!null "", + ? !!str "block key\n" + : !!seq [ + !!str "one", + !!str "two", + ] +} diff --git a/src/test/resources/pyyaml/spec-10-13.data b/src/test/resources/pyyaml/spec-10-13.data new file mode 100644 index 00000000..b5b97db1 --- /dev/null +++ b/src/test/resources/pyyaml/spec-10-13.data @@ -0,0 +1,5 @@ +? explicit key # implicit value +? | + block key +: - one # explicit in-line + - two # block value diff --git a/src/test/resources/pyyaml/spec-10-14.canonical b/src/test/resources/pyyaml/spec-10-14.canonical new file mode 100644 index 00000000..e87c8805 --- /dev/null +++ b/src/test/resources/pyyaml/spec-10-14.canonical @@ -0,0 +1,11 @@ +%YAML 1.1 +--- +!!map { + ? !!str "plain key" + : !!null "", + ? !!str "quoted key" + : !!seq [ + !!str "one", + !!str "two", + ] +} diff --git a/src/test/resources/pyyaml/spec-10-14.data b/src/test/resources/pyyaml/spec-10-14.data new file mode 100644 index 00000000..7f5995ca --- /dev/null +++ b/src/test/resources/pyyaml/spec-10-14.data @@ -0,0 +1,4 @@ +plain key: # empty value +"quoted key": +- one # explicit next-line +- two # block value diff --git a/src/test/resources/pyyaml/spec-10-15.canonical b/src/test/resources/pyyaml/spec-10-15.canonical new file mode 100644 index 00000000..85fbbd06 --- /dev/null +++ b/src/test/resources/pyyaml/spec-10-15.canonical @@ -0,0 +1,18 @@ +%YAML 1.1 +--- +!!seq [ + !!map { + ? !!str "sun" + : !!str "yellow" + }, + !!map { + ? !!map { + ? !!str "earth" + : !!str "blue" + } + : !!map { + ? !!str "moon" + : !!str "white" + } + } +] diff --git a/src/test/resources/pyyaml/spec-10-15.data b/src/test/resources/pyyaml/spec-10-15.data new file mode 100644 index 00000000..d675cfd6 --- /dev/null +++ b/src/test/resources/pyyaml/spec-10-15.data @@ -0,0 +1,3 @@ +- sun: yellow +- ? earth: blue + : moon: white diff --git a/src/test/resources/pyyaml/str.data b/src/test/resources/pyyaml/str.data new file mode 100644 index 00000000..7cbdb7c6 --- /dev/null +++ b/src/test/resources/pyyaml/str.data @@ -0,0 +1 @@ +- abcd diff --git a/src/test/resources/pyyaml/tags.events b/src/test/resources/pyyaml/tags.events new file mode 100644 index 00000000..bb93dce1 --- /dev/null +++ b/src/test/resources/pyyaml/tags.events @@ -0,0 +1,12 @@ +- !StreamStart +- !DocumentStart +- !SequenceStart +- !Scalar { value: 'data' } +#- !Scalar { tag: '!', value: 'data' } +- !Scalar { tag: 'tag:yaml.org,2002:str', value: 'data' } +- !Scalar { tag: '!myfunnytag', value: 'data' } +- !Scalar { tag: '!my!ugly!tag', value: 'data' } +- !Scalar { tag: 'tag:my.domain.org,2002:data!? #', value: 'data' } +- !SequenceEnd +- !DocumentEnd +- !StreamEnd diff --git a/src/test/resources/pyyaml/test_mark.marks b/src/test/resources/pyyaml/test_mark.marks new file mode 100644 index 00000000..cf257b46 --- /dev/null +++ b/src/test/resources/pyyaml/test_mark.marks @@ -0,0 +1,38 @@ +---
+*The first line.
+The last line.
+---
+The first*line.
+The last line.
+---
+The first line.*
+The last line.
+---
+The first line.
+*The last line.
+---
+The first line.
+The last*line.
+---
+The first line.
+The last line.*
+---
+The first line.
+*The selected line.
+The last line.
+---
+The first line.
+The selected*line.
+The last line.
+---
+The first line.
+The selected line.*
+The last line.
+---
+*The only line.
+---
+The only*line.
+---
+The only line.*
+---
+Loooooooooooooooooooooooooooooooooooooooooooooong*Liiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiine
diff --git a/src/test/resources/pyyaml/timestamp-bugs.data b/src/test/resources/pyyaml/timestamp-bugs.data new file mode 100644 index 00000000..721d2908 --- /dev/null +++ b/src/test/resources/pyyaml/timestamp-bugs.data @@ -0,0 +1,6 @@ +- 2001-12-14 21:59:43.10 -5:30 +- 2001-12-14 21:59:43.10 +5:30 +- 2001-12-14 21:59:43.00101 +- 2001-12-14 21:59:43+1 +- 2001-12-14 21:59:43-1:30 +- 2005-07-08 17:35:04.517600 diff --git a/src/test/resources/pyyaml/timestamp.data b/src/test/resources/pyyaml/timestamp.data new file mode 100644 index 00000000..7d214ce4 --- /dev/null +++ b/src/test/resources/pyyaml/timestamp.data @@ -0,0 +1,5 @@ +- 2001-12-15T02:59:43.1Z +- 2001-12-14t21:59:43.10-05:00 +- 2001-12-14 21:59:43.10 -5 +- 2001-12-15 2:59:43.10 +- 2002-12-14 diff --git a/src/test/resources/pyyaml/unacceptable-key.loader-error b/src/test/resources/pyyaml/unacceptable-key.loader-error new file mode 100644 index 00000000..d748e375 --- /dev/null +++ b/src/test/resources/pyyaml/unacceptable-key.loader-error @@ -0,0 +1,4 @@ +--- +? - foo + - bar +: baz diff --git a/src/test/resources/pyyaml/unclosed-bracket.loader-error b/src/test/resources/pyyaml/unclosed-bracket.loader-error new file mode 100644 index 00000000..8c820777 --- /dev/null +++ b/src/test/resources/pyyaml/unclosed-bracket.loader-error @@ -0,0 +1,6 @@ +test: + - [ foo: bar +# comment the rest of the stream to let the scanner detect the problem. +# - baz +#"we could have detected the unclosed bracket on the above line, but this would forbid such syntax as": { +#} diff --git a/src/test/resources/pyyaml/unclosed-quoted-scalar.loader-error b/src/test/resources/pyyaml/unclosed-quoted-scalar.loader-error new file mode 100644 index 00000000..85374294 --- /dev/null +++ b/src/test/resources/pyyaml/unclosed-quoted-scalar.loader-error @@ -0,0 +1,2 @@ +'foo + bar diff --git a/src/test/resources/pyyaml/undefined-anchor.loader-error b/src/test/resources/pyyaml/undefined-anchor.loader-error new file mode 100644 index 00000000..94691032 --- /dev/null +++ b/src/test/resources/pyyaml/undefined-anchor.loader-error @@ -0,0 +1,3 @@ +- foo +- &bar baz +- *bat diff --git a/src/test/resources/pyyaml/undefined-constructor.loader-error b/src/test/resources/pyyaml/undefined-constructor.loader-error new file mode 100644 index 00000000..9a37ccc9 --- /dev/null +++ b/src/test/resources/pyyaml/undefined-constructor.loader-error @@ -0,0 +1 @@ +--- !foo bar diff --git a/src/test/resources/pyyaml/undefined-tag-handle.loader-error b/src/test/resources/pyyaml/undefined-tag-handle.loader-error new file mode 100644 index 00000000..82ba335c --- /dev/null +++ b/src/test/resources/pyyaml/undefined-tag-handle.loader-error @@ -0,0 +1 @@ +--- !foo!bar baz diff --git a/src/test/resources/pyyaml/unsupported-version.emitter-error b/src/test/resources/pyyaml/unsupported-version.emitter-error new file mode 100644 index 00000000..f9c61976 --- /dev/null +++ b/src/test/resources/pyyaml/unsupported-version.emitter-error @@ -0,0 +1,5 @@ +- !StreamStart +- !DocumentStart { version: [5,6] } +- !Scalar { value: foo } +- !DocumentEnd +- !StreamEnd diff --git a/src/test/resources/pyyaml/value.data b/src/test/resources/pyyaml/value.data new file mode 100644 index 00000000..c5b7680c --- /dev/null +++ b/src/test/resources/pyyaml/value.data @@ -0,0 +1 @@ +- = diff --git a/src/test/resources/pyyaml/yaml.data b/src/test/resources/pyyaml/yaml.data new file mode 100644 index 00000000..a4bb3f8e --- /dev/null +++ b/src/test/resources/pyyaml/yaml.data @@ -0,0 +1,3 @@ +- !!yaml '!' +- !!yaml '&' +- !!yaml '*' diff --git a/src/test/resources/reader/unicode-16be.txt b/src/test/resources/reader/unicode-16be.txt Binary files differnew file mode 100644 index 00000000..18e8f256 --- /dev/null +++ b/src/test/resources/reader/unicode-16be.txt diff --git a/src/test/resources/reader/unicode-16le.txt b/src/test/resources/reader/unicode-16le.txt Binary files differnew file mode 100644 index 00000000..2f845860 --- /dev/null +++ b/src/test/resources/reader/unicode-16le.txt diff --git a/src/test/resources/reader/utf-8.txt b/src/test/resources/reader/utf-8.txt new file mode 100644 index 00000000..b0540d22 --- /dev/null +++ b/src/test/resources/reader/utf-8.txt @@ -0,0 +1 @@ +test
\ No newline at end of file diff --git a/src/test/resources/specification/example2_1.yaml b/src/test/resources/specification/example2_1.yaml new file mode 100644 index 00000000..3cb7d7a6 --- /dev/null +++ b/src/test/resources/specification/example2_1.yaml @@ -0,0 +1,3 @@ +- Mark McGwire
+- Sammy Sosa
+- Ken Griffey
diff --git a/src/test/resources/specification/example2_10.yaml b/src/test/resources/specification/example2_10.yaml new file mode 100644 index 00000000..f9e23baa --- /dev/null +++ b/src/test/resources/specification/example2_10.yaml @@ -0,0 +1,8 @@ +---
+hr:
+ - Mark McGwire
+ # Following node labeled SS
+ - &SS Sammy Sosa
+rbi:
+ - *SS # Subsequent occurrence
+ - Ken Griffey
diff --git a/src/test/resources/specification/example2_11.yaml b/src/test/resources/specification/example2_11.yaml new file mode 100644 index 00000000..bc991779 --- /dev/null +++ b/src/test/resources/specification/example2_11.yaml @@ -0,0 +1,9 @@ +? - Detroit Tigers
+ - Chicago cubs
+:
+ - 2001-07-23
+
+? [ New York Yankees,
+ Atlanta Braves ]
+: [ 2001-07-02, 2001-08-12,
+ 2001-08-14 ]
diff --git a/src/test/resources/specification/example2_12.yaml b/src/test/resources/specification/example2_12.yaml new file mode 100644 index 00000000..6c120ac5 --- /dev/null +++ b/src/test/resources/specification/example2_12.yaml @@ -0,0 +1,8 @@ +---
+# products purchased
+- item : Super Hoop
+ quantity: 1
+- item : Basketball
+ quantity: 4
+- item : Big Shoes
+ quantity: 1
diff --git a/src/test/resources/specification/example2_13.yaml b/src/test/resources/specification/example2_13.yaml new file mode 100644 index 00000000..e9276385 --- /dev/null +++ b/src/test/resources/specification/example2_13.yaml @@ -0,0 +1,4 @@ +# ASCII Art
+--- |
+ \//||\/||
+ // || ||__
diff --git a/src/test/resources/specification/example2_14.yaml b/src/test/resources/specification/example2_14.yaml new file mode 100644 index 00000000..f39eb533 --- /dev/null +++ b/src/test/resources/specification/example2_14.yaml @@ -0,0 +1,4 @@ +---
+ Mark McGwire's
+ year was crippled
+ by a knee injury.
diff --git a/src/test/resources/specification/example2_15.yaml b/src/test/resources/specification/example2_15.yaml new file mode 100644 index 00000000..fc92a53e --- /dev/null +++ b/src/test/resources/specification/example2_15.yaml @@ -0,0 +1,8 @@ +>
+ Sammy Sosa completed another
+ fine season with great stats.
+
+ 63 Home Runs
+ 0.288 Batting Average
+
+ What a year!
diff --git a/src/test/resources/specification/example2_16.yaml b/src/test/resources/specification/example2_16.yaml new file mode 100644 index 00000000..2e7ea487 --- /dev/null +++ b/src/test/resources/specification/example2_16.yaml @@ -0,0 +1,7 @@ +name: Mark McGwire
+accomplishment: >
+ Mark set a major league
+ home run record in 1998.
+stats: |
+ 65 Home Runs
+ 0.278 Batting Average
diff --git a/src/test/resources/specification/example2_17.yaml b/src/test/resources/specification/example2_17.yaml new file mode 100644 index 00000000..592d4ae3 --- /dev/null +++ b/src/test/resources/specification/example2_17.yaml @@ -0,0 +1,7 @@ +unicode: "Sosa did fine.\u263A"
+control: "\b1998\t1999\t2000\n"
+hexesc: "\x0D\x0A is \r\n"
+
+single: '"Howdy!" he cried.'
+quoted: ' # not a ''comment''.'
+tie-fighter: '|\-*-/|'
diff --git a/src/test/resources/specification/example2_17_control.yaml b/src/test/resources/specification/example2_17_control.yaml new file mode 100644 index 00000000..b8447d9c --- /dev/null +++ b/src/test/resources/specification/example2_17_control.yaml @@ -0,0 +1,2 @@ +control: "\b1998\t1999\t2000\n"
+
diff --git a/src/test/resources/specification/example2_17_hexesc.yaml b/src/test/resources/specification/example2_17_hexesc.yaml new file mode 100644 index 00000000..c3235305 --- /dev/null +++ b/src/test/resources/specification/example2_17_hexesc.yaml @@ -0,0 +1,2 @@ +hexesc: "\x0D\x0A is \r\n"
+
diff --git a/src/test/resources/specification/example2_17_quoted.yaml b/src/test/resources/specification/example2_17_quoted.yaml new file mode 100644 index 00000000..8e7ca05b --- /dev/null +++ b/src/test/resources/specification/example2_17_quoted.yaml @@ -0,0 +1,2 @@ +quoted: ' # not a ''comment''.'
+
diff --git a/src/test/resources/specification/example2_17_single.yaml b/src/test/resources/specification/example2_17_single.yaml new file mode 100644 index 00000000..8f69b6cb --- /dev/null +++ b/src/test/resources/specification/example2_17_single.yaml @@ -0,0 +1 @@ +single: '"Howdy!" he cried.'
diff --git a/src/test/resources/specification/example2_17_tie_fighter.yaml b/src/test/resources/specification/example2_17_tie_fighter.yaml new file mode 100644 index 00000000..3d3928f4 --- /dev/null +++ b/src/test/resources/specification/example2_17_tie_fighter.yaml @@ -0,0 +1 @@ +tie-fighter: '|\-*-/|'
diff --git a/src/test/resources/specification/example2_17_unicode.yaml b/src/test/resources/specification/example2_17_unicode.yaml new file mode 100644 index 00000000..60ec8085 --- /dev/null +++ b/src/test/resources/specification/example2_17_unicode.yaml @@ -0,0 +1,2 @@ +unicode: "Sosa did fine.\u263A"
+
diff --git a/src/test/resources/specification/example2_18.yaml b/src/test/resources/specification/example2_18.yaml new file mode 100644 index 00000000..76fe0d26 --- /dev/null +++ b/src/test/resources/specification/example2_18.yaml @@ -0,0 +1,6 @@ +plain:
+ This unquoted scalar
+ spans many lines.
+
+quoted: "So does this
+ quoted scalar.\n"
diff --git a/src/test/resources/specification/example2_19.yaml b/src/test/resources/specification/example2_19.yaml new file mode 100644 index 00000000..4a1c0700 --- /dev/null +++ b/src/test/resources/specification/example2_19.yaml @@ -0,0 +1,5 @@ +canonical: 12345
+decimal: +12_345
+sexagesimal: 3:25:45
+octal: 014
+hexadecimal: 0xC
diff --git a/src/test/resources/specification/example2_2.yaml b/src/test/resources/specification/example2_2.yaml new file mode 100644 index 00000000..efd138d5 --- /dev/null +++ b/src/test/resources/specification/example2_2.yaml @@ -0,0 +1,3 @@ +hr: 65 # Home runs
+avg: 0.278 # Batting average
+rbi: 147 # Runs Batted In
diff --git a/src/test/resources/specification/example2_20.yaml b/src/test/resources/specification/example2_20.yaml new file mode 100644 index 00000000..ceb1fd0d --- /dev/null +++ b/src/test/resources/specification/example2_20.yaml @@ -0,0 +1,6 @@ +canonical: 1.23015e+3
+exponential: 12.3015e+02
+sexagesimal: 20:30.15
+fixed: 1_230.15
+negative infinity: -.inf
+not a number: .NaN
diff --git a/src/test/resources/specification/example2_21.yaml b/src/test/resources/specification/example2_21.yaml new file mode 100644 index 00000000..d017affe --- /dev/null +++ b/src/test/resources/specification/example2_21.yaml @@ -0,0 +1,4 @@ +null: ~
+true: yes
+false: no
+string: '12345'
diff --git a/src/test/resources/specification/example2_22.yaml b/src/test/resources/specification/example2_22.yaml new file mode 100644 index 00000000..d4781f74 --- /dev/null +++ b/src/test/resources/specification/example2_22.yaml @@ -0,0 +1,4 @@ +canonical: 2001-12-15T02:59:43.1Z
+iso8601: 2001-12-14t21:59:43.10-05:00
+spaced: 2001-12-14 21:59:43.10 -5
+date: 2002-12-14
diff --git a/src/test/resources/specification/example2_23.yaml b/src/test/resources/specification/example2_23.yaml new file mode 100644 index 00000000..310d4723 --- /dev/null +++ b/src/test/resources/specification/example2_23.yaml @@ -0,0 +1,14 @@ +---
+not-date: !!str 2002-04-28
+
+picture: !!binary "\
+ R0lGODlhDAAMAIQAAP//9/X\
+ 17unp5WZmZgAAAOfn515eXv\
+ Pz7Y6OjuDg4J+fn5OTk6enp\
+ 56enmleECcgggoBADs="
+
+application specific tag: !something |
+ The semantics of the tag
+ above may be different for
+ different documents.
+
diff --git a/src/test/resources/specification/example2_23_application.yaml b/src/test/resources/specification/example2_23_application.yaml new file mode 100644 index 00000000..a77e4ef2 --- /dev/null +++ b/src/test/resources/specification/example2_23_application.yaml @@ -0,0 +1,5 @@ +---
+application specific tag: !something |
+ The semantics of the tag
+ above may be different for
+ different documents.
diff --git a/src/test/resources/specification/example2_23_non_date.yaml b/src/test/resources/specification/example2_23_non_date.yaml new file mode 100644 index 00000000..58a6a327 --- /dev/null +++ b/src/test/resources/specification/example2_23_non_date.yaml @@ -0,0 +1,3 @@ +---
+not-date: !!str 2002-04-28
+
diff --git a/src/test/resources/specification/example2_23_picture.yaml b/src/test/resources/specification/example2_23_picture.yaml new file mode 100644 index 00000000..1229d324 --- /dev/null +++ b/src/test/resources/specification/example2_23_picture.yaml @@ -0,0 +1,9 @@ +---
+picture: !!binary "\
+ R0lGODlhDAAMAIQAAP//9/X\
+ 17unp5WZmZgAAAOfn515eXv\
+ Pz7Y6OjuDg4J+fn5OTk6enp\
+ 56enmleECcgggoBADs="
+
+
+
\ No newline at end of file diff --git a/src/test/resources/specification/example2_24.yaml b/src/test/resources/specification/example2_24.yaml new file mode 100644 index 00000000..d97247ff --- /dev/null +++ b/src/test/resources/specification/example2_24.yaml @@ -0,0 +1,14 @@ +%TAG ! tag:clarkevans.com,2002:
+--- !shape
+ # Use the ! handle for presenting
+ # tag:clarkevans.com,2002:circle
+- !circle
+ center: &ORIGIN {x: 73, y: 129}
+ radius: 7
+- !line
+ start: *ORIGIN
+ finish: { x: 89, y: 102 }
+- !label
+ start: *ORIGIN
+ color: 0xFFEEBB
+ text: Pretty vector drawing.
diff --git a/src/test/resources/specification/example2_24_dumped.yaml b/src/test/resources/specification/example2_24_dumped.yaml new file mode 100644 index 00000000..f7e97662 --- /dev/null +++ b/src/test/resources/specification/example2_24_dumped.yaml @@ -0,0 +1,11 @@ +!shape
+- !circle
+ center: &id001 {x: 73, y: 129}
+ radius: 7
+- !line
+ finish: {x: 89, y: 102}
+ start: *id001
+- !label
+ color: 0xFFEEBB
+ start: *id001
+ text: Pretty vector drawing.
\ No newline at end of file diff --git a/src/test/resources/specification/example2_25.yaml b/src/test/resources/specification/example2_25.yaml new file mode 100644 index 00000000..be58da2e --- /dev/null +++ b/src/test/resources/specification/example2_25.yaml @@ -0,0 +1,7 @@ +# sets are represented as a
+# mapping where each key is
+# associated with the empty string
+--- !!set
+? Mark McGwire
+? Sammy Sosa
+? Ken Griff
diff --git a/src/test/resources/specification/example2_26.yaml b/src/test/resources/specification/example2_26.yaml new file mode 100644 index 00000000..0a70a642 --- /dev/null +++ b/src/test/resources/specification/example2_26.yaml @@ -0,0 +1,7 @@ +# ordered maps are represented as
+# a sequence of mappings, with
+# each mapping having one key
+--- !!omap
+- Mark McGwire: 65
+- Sammy Sosa: 63
+- Ken Griffy: 58
diff --git a/src/test/resources/specification/example2_27.yaml b/src/test/resources/specification/example2_27.yaml new file mode 100644 index 00000000..8eda5e0f --- /dev/null +++ b/src/test/resources/specification/example2_27.yaml @@ -0,0 +1,29 @@ +--- !<tag:clarkevans.com,2002:invoice>
+invoice: 34843
+date : 2001-01-23
+billTo: &id001
+ given : Chris
+ family : Dumars
+ address:
+ lines: |
+ 458 Walkman Dr.
+ Suite #292
+ city : Royal Oak
+ state : MI
+ postal : 48046
+shipTo: *id001
+product:
+ - sku : BL394D
+ quantity : 4
+ description : Basketball
+ price : 450.00
+ - sku : BL4438H
+ quantity : 1
+ description : Super Hoop
+ price : 2392.00
+tax : 251.42
+total: 4443.52
+comments:
+ Late afternoon is best.
+ Backup contact is Nancy
+ Billsmer @ 338-4338.
diff --git a/src/test/resources/specification/example2_27_dumped.yaml b/src/test/resources/specification/example2_27_dumped.yaml new file mode 100644 index 00000000..d0f22ac7 --- /dev/null +++ b/src/test/resources/specification/example2_27_dumped.yaml @@ -0,0 +1,18 @@ +!!org.yaml.snakeyaml.Invoice
+billTo: &id001
+ address: {city: Royal Oak, lines: '458 Walkman Dr.
+
+ Suite #292
+
+ ', postal: '48046', state: MI}
+ family: Dumars
+ given: Chris
+comments: Late afternoon is best. Backup contact is Nancy Billsmer @ 338-4338.
+date: '2001-01-23'
+invoice: 34843
+product:
+- {sku: BL394D, quantity: 4, description: Basketball, price: 450.0}
+- {sku: BL4438H, quantity: 1, description: Super Hoop, price: 2392.0}
+shipTo: *id001
+tax: 251.42
+total: 4443.52
\ No newline at end of file diff --git a/src/test/resources/specification/example2_28.yaml b/src/test/resources/specification/example2_28.yaml new file mode 100644 index 00000000..5880ac3a --- /dev/null +++ b/src/test/resources/specification/example2_28.yaml @@ -0,0 +1,29 @@ +---
+Time: 2001-11-23 15:01:42 -5
+User: ed
+Warning:
+ This is an error message
+ for the log file
+---
+Time: 2001-11-23 15:02:31 -5
+User: ed
+Warning:
+ A slightly different error
+ message.
+---
+Date: 2001-11-23 15:03:17 -5
+User: ed
+Fatal:
+ Unknown variable "bar"
+Stack:
+ - file: TopClass.py
+ line: 23
+ code: |
+ x = MoreObject("345\n")
+ - file: MoreClass.py
+ line: 58
+ code: |-
+ foo = bar
+
+
+
diff --git a/src/test/resources/specification/example2_3.yaml b/src/test/resources/specification/example2_3.yaml new file mode 100644 index 00000000..e0429fa0 --- /dev/null +++ b/src/test/resources/specification/example2_3.yaml @@ -0,0 +1,8 @@ +american:
+ - Boston Red Sox
+ - Detroit Tigers
+ - New York Yankees
+national:
+ - New York Mets
+ - Chicago Cubs
+ - Atlanta Braves
\ No newline at end of file diff --git a/src/test/resources/specification/example2_4.yaml b/src/test/resources/specification/example2_4.yaml new file mode 100644 index 00000000..9bfb6cc9 --- /dev/null +++ b/src/test/resources/specification/example2_4.yaml @@ -0,0 +1,8 @@ +-
+ name: Mark McGwire
+ hr: 65
+ avg: 0.278
+-
+ name: Sammy Sosa
+ hr: 63
+ avg: 0.288
diff --git a/src/test/resources/specification/example2_5.yaml b/src/test/resources/specification/example2_5.yaml new file mode 100644 index 00000000..260ce2dc --- /dev/null +++ b/src/test/resources/specification/example2_5.yaml @@ -0,0 +1,3 @@ +- [name , hr, avg ]
+- [Mark McGwire, 65, 0.278]
+- [Sammy Sosa , 63, 0.288]
diff --git a/src/test/resources/specification/example2_6.yaml b/src/test/resources/specification/example2_6.yaml new file mode 100644 index 00000000..f1a3c1ef --- /dev/null +++ b/src/test/resources/specification/example2_6.yaml @@ -0,0 +1,5 @@ +Mark McGwire: {hr: 65, avg: 0.278}
+Sammy Sosa: {
+ hr: 63,
+ avg: 0.288
+ }
diff --git a/src/test/resources/specification/example2_7.yaml b/src/test/resources/specification/example2_7.yaml new file mode 100644 index 00000000..1ea21489 --- /dev/null +++ b/src/test/resources/specification/example2_7.yaml @@ -0,0 +1,10 @@ +# Ranking of 1998 home runs
+---
+- Mark McGwire
+- Sammy Sosa
+- Ken Griffey
+
+# Team ranking
+---
+- Chicago Cubs
+- St Louis Cardinals
diff --git a/src/test/resources/specification/example2_8.yaml b/src/test/resources/specification/example2_8.yaml new file mode 100644 index 00000000..4c286c37 --- /dev/null +++ b/src/test/resources/specification/example2_8.yaml @@ -0,0 +1,10 @@ +---
+time: 20:03:20
+player: Sammy Sosa
+action: strike (miss)
+...
+---
+time: 20:03:47
+player: Sammy Sosa
+action: grand slam
+...
diff --git a/src/test/resources/specification/example2_9.yaml b/src/test/resources/specification/example2_9.yaml new file mode 100644 index 00000000..21c27047 --- /dev/null +++ b/src/test/resources/specification/example2_9.yaml @@ -0,0 +1,8 @@ +---
+hr: # 1998 hr ranking
+ - Mark McGwire
+ - Sammy Sosa
+rbi:
+ # 1998 rbi ranking
+ - Sammy Sosa
+ - Ken Griffey
diff --git a/src/test/resources/specification/types/map.yaml b/src/test/resources/specification/types/map.yaml new file mode 100644 index 00000000..7e57a65e --- /dev/null +++ b/src/test/resources/specification/types/map.yaml @@ -0,0 +1,6 @@ +# Unordered set of key: value pairs.
+Block style: !!map
+ Clark : Evans
+ Brian : Ingerson
+ Oren : Ben-Kiki
+Flow style: !!map { Clark: Evans, Brian: Ingerson, Oren: Ben-Kiki }
diff --git a/src/test/resources/specification/types/map_mixed_tags.yaml b/src/test/resources/specification/types/map_mixed_tags.yaml new file mode 100644 index 00000000..ba1b5e09 --- /dev/null +++ b/src/test/resources/specification/types/map_mixed_tags.yaml @@ -0,0 +1,6 @@ +# Unordered set of key: value pairs.
+Block style: !<tag:yaml.org,2002:map>
+ Clark : Evans
+ Brian : Ingerson
+ Oren : Ben-Kiki
+Flow style: { Clark: Evans, Brian: Ingerson, Oren: Ben-Kiki }
diff --git a/src/test/resources/specification/types/merge.yaml b/src/test/resources/specification/types/merge.yaml new file mode 100644 index 00000000..00f189ab --- /dev/null +++ b/src/test/resources/specification/types/merge.yaml @@ -0,0 +1,27 @@ +---
+- &CENTER { x: 1, y: 2 }
+- &LEFT { x: 0, y: 2 }
+- &BIG { r: 10 }
+- &SMALL { r: 1 }
+
+# All the following maps are equal:
+
+- # Explicit keys
+ x: 1
+ y: 2
+ r: 10
+ label: center/big
+
+- # Merge one map
+ << : *CENTER
+ r: 10
+ label: center/big
+
+- # Merge multiple maps
+ << : [ *CENTER, *BIG ]
+ label: center/big
+
+- # Override
+ << : [ *BIG, *LEFT, *SMALL ]
+ x: 1
+ label: center/big
diff --git a/src/test/resources/specification/types/omap.yaml b/src/test/resources/specification/types/omap.yaml new file mode 100644 index 00000000..5e0a8123 --- /dev/null +++ b/src/test/resources/specification/types/omap.yaml @@ -0,0 +1,8 @@ +# Explicitly typed ordered map (dictionary).
+Bestiary: !!omap
+ - aardvark: African pig-like ant eater. Ugly.
+ - anteater: South-American ant eater. Two species.
+ - anaconda: South-American constrictor snake. Scaly.
+ # Etc.
+# Flow style
+Numbers: !!omap [ one: 1, two: 2, three : 3 ]
diff --git a/src/test/resources/specification/types/pairs.yaml b/src/test/resources/specification/types/pairs.yaml new file mode 100644 index 00000000..34acf770 --- /dev/null +++ b/src/test/resources/specification/types/pairs.yaml @@ -0,0 +1,7 @@ +# Explicitly typed pairs.
+Block tasks: !!pairs
+ - meeting: with team.
+ - meeting: with boss.
+ - break: lunch.
+ - meeting: with client.
+Flow tasks: !!pairs [ meeting: with team, meeting: with boss ]
diff --git a/src/test/resources/specification/types/seq.yaml b/src/test/resources/specification/types/seq.yaml new file mode 100644 index 00000000..dd690e2d --- /dev/null +++ b/src/test/resources/specification/types/seq.yaml @@ -0,0 +1,14 @@ +# Ordered sequence of nodes
+Block style: !!seq
+- Mercury # Rotates - no light/dark sides.
+- Venus # Deadliest. Aptly named.
+- Earth # Mostly dirt.
+- Mars # Seems empty.
+- Jupiter # The king.
+- Saturn # Pretty.
+- Uranus # Where the sun hardly shines.
+- Neptune # Boring. No rings.
+- Pluto # You call this a planet?
+Flow style: !!seq [ Mercury, Venus, Earth, Mars, # Rocks
+ Jupiter, Saturn, Uranus, Neptune, # Gas
+ Pluto ] # Overrated
diff --git a/src/test/resources/specification/types/set.yaml b/src/test/resources/specification/types/set.yaml new file mode 100644 index 00000000..19406eb0 --- /dev/null +++ b/src/test/resources/specification/types/set.yaml @@ -0,0 +1,7 @@ +# Explicitly typed set.
+baseball players: !!set
+ ? Mark McGwire
+ ? Sammy Sosa
+ ? Ken Griffey
+# Flow style
+baseball teams: !!set { Boston Red Sox, Detroit Tigers, New York Yankees }
diff --git a/src/test/resources/specification/types/v.yaml b/src/test/resources/specification/types/v.yaml new file mode 100644 index 00000000..0fdc8fb7 --- /dev/null +++ b/src/test/resources/specification/types/v.yaml @@ -0,0 +1,4 @@ +--- # New schema
+link with:
+ - = : library1.dll
+ version: 1.2
diff --git a/src/test/resources/specification/types/value.yaml b/src/test/resources/specification/types/value.yaml new file mode 100644 index 00000000..8f83a6e2 --- /dev/null +++ b/src/test/resources/specification/types/value.yaml @@ -0,0 +1,10 @@ +--- # Old schema
+link with:
+ - library1.dll
+ - library2.dll
+--- # New schema
+link with:
+ - = : library1.dll
+ version: 1.2
+ - = : library2.dll
+ version: 2.3
|