ruby/test/psych/test_parser.rb
tenderlove 7d984d76ba merge revision(s) 32578,33401,33403,33404,33531,33655,33679,33809,33900,33965,34067,34069,34087,34328,34330,34527,34772,34783,34839,34914,34953,34954,35153: [Backport #6212]
* ext/psych/lib/psych.rb: updating version to match gem
	* ext/psych/psych.gemspec: ditto
	* ext/psych/lib/psych/visitors/to_ruby.rb: fixing deprecation warning

	* ext/psych/lib/psych.rb: define a new BadAlias error class.

	* ext/psych/lib/psych/visitors/to_ruby.rb: raise an exception when
	  deserializing an alias that does not exist.

	* test/psych/test_merge_keys.rb: corresponding test.

	* ext/psych/lib/psych.rb (load, parse): stop parsing or loading after
	  the first document has been parsed.

	* test/psych/test_stream.rb: pertinent tests.

	* ext/psych/lib/psych.rb (parse_stream, load_stream): if a block is
	  given, documents will be yielded to the block as they are parsed.
	  [ruby-core:42404] [Bug #5978]

	* ext/psych/lib/psych/handlers/document_stream.rb: add a handler that
	  yields documents as they are parsed

	* test/psych/test_stream.rb: corresponding tests.

	* ext/psych/lib/psych/core_ext.rb: only extend Kernel if IRB is loaded
	  in order to stop method pollution.

	* ext/psych/lib/psych.rb: default open YAML files with utf8 external
	  encoding. [ruby-core:42967]
	* test/psych/test_tainted.rb: ditto

	* ext/psych/parser.c: prevent a memory leak by protecting calls to
	  handler callbacks.
	* test/psych/test_parser.rb: test to demonstrate leak.

	* ext/psych/parser.c: set parser encoding based on the YAML input
	  rather than user configuration.
	* test/psych/test_encoding.rb: corresponding tests.
	* test/psych/test_parser.rb: ditto
	* test/psych/test_tainted.rb: ditto

	* ext/psych/parser.c: removed external encoding setter, allow parser
	  to be reused.
	* ext/psych/lib/psych/parser.rb: added external encoding setter.
	* test/psych/test_parser.rb: test parser reuse

	* ext/psych/lib/psych/visitors/to_ruby.rb: Added support for loading
	  subclasses of String with ivars
	* ext/psych/lib/psych/visitors/yaml_tree.rb: Added support for dumping
	  subclasses of String with ivars
	* test/psych/test_string.rb: corresponding tests

	* ext/psych/lib/psych/visitors/to_ruby.rb: Added ability to load array
	  subclasses with ivars.
	* ext/psych/lib/psych/visitors/yaml_tree.rb: Added ability to dump
	  array subclasses with ivars.
	* test/psych/test_array.rb: corresponding tests

	* ext/psych/emitter.c: fixing clang warnings. Thanks Joey!

	* ext/psych/lib/psych/visitors/to_ruby.rb: BigDecimals can be restored
	  from YAML.
	* ext/psych/lib/psych/visitors/yaml_tree.rb: BigDecimals can be dumped
	  to YAML.
	* test/psych/test_numeric.rb: tests for BigDecimal serialization

	* ext/psych/lib/psych/scalar_scanner.rb: Strings that look like dates
	  should be treated as strings and not dates.

	* test/psych/test_scalar_scanner.rb: corresponding tests.

	* ext/psych/lib/psych.rb (module Psych): parse and load methods take
	  an optional file name that is used when raising Psych::SyntaxError
	  exceptions
	* ext/psych/lib/psych/syntax_error.rb (module Psych): allow nil file
	  names and handle nil file names in the exception message
	* test/psych/test_exception.rb (module Psych): Tests for changes.

	* ext/psych/parser.c (parse): parse method can take an option file
	  name for use in exception messages.
	* test/psych/test_parser.rb: corresponding tests.

	* ext/psych/lib/psych.rb: remove autoload from psych
	* ext/psych/lib/psych/json.rb: ditto

	* ext/psych/lib/psych/tree_builder.rb: dump complex numbers,
	  rationals, etc with reference ids.
	* ext/psych/lib/psych/visitors/yaml_tree.rb: ditto
	* ext/psych/lib/psych/visitors/to_ruby.rb: loading complex numbers,
	  rationals, etc with reference ids.
	* test/psych/test_object_references.rb: corresponding tests

	* ext/psych/lib/psych/scalar_scanner.rb: make sure strings that look
	  like base 60 numbers are serialized as quoted strings.
	* test/psych/test_string.rb: test for change.

	* ext/psych/parser.c: remove unused variable.

	* ext/psych/lib/psych/syntax_error.rb: Add file, line, offset, and
	  message attributes during parse failure.
	* ext/psych/parser.c: Update parser to raise exception with correct
	  values.
	* test/psych/test_exception.rb: corresponding tests.

	* ext/psych/parser.c (parse): Use context_mark for indicating error
	  line and column.

	* ext/psych/lib/psych/scalar_scanner.rb: use normal begin / rescue
	  since postfix rescue cannot receive the exception class. Thanks
	  nagachika!

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_9_3@35165 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-03-29 01:25:11 +00:00

332 lines
8.5 KiB
Ruby

# coding: utf-8
require 'psych/helper'
module Psych
class TestParser < TestCase
class EventCatcher < Handler
attr_accessor :parser
attr_reader :calls, :marks
def initialize
@parser = nil
@calls = []
@marks = []
end
(Handler.instance_methods(true) -
Object.instance_methods).each do |m|
class_eval %{
def #{m} *args
super
@marks << @parser.mark if @parser
@calls << [:#{m}, args]
end
}
end
end
def setup
super
@handler = EventCatcher.new
@parser = Psych::Parser.new @handler
@handler.parser = @parser
end
def test_exception_memory_leak
yaml = <<-eoyaml
%YAML 1.1
%TAG ! tag:tenderlovemaking.com,2009:
--- &ponies
- first element
- *ponies
- foo: bar
...
eoyaml
[:start_stream, :start_document, :end_document, :alias, :scalar,
:start_sequence, :end_sequence, :start_mapping, :end_mapping,
:end_stream].each do |method|
klass = Class.new(Psych::Handler) do
define_method(method) do |*args|
raise
end
end
parser = Psych::Parser.new klass.new
2.times {
assert_raises(RuntimeError, method.to_s) do
parser.parse yaml
end
}
end
end
def test_multiparse
3.times do
@parser.parse '--- foo'
end
end
def test_filename
ex = assert_raises(Psych::SyntaxError) do
@parser.parse '--- `', 'omg!'
end
assert_match 'omg!', ex.message
end
def test_line_numbers
assert_equal 0, @parser.mark.line
@parser.parse "---\n- hello\n- world"
line_calls = @handler.marks.map(&:line).zip(@handler.calls.map(&:first))
assert_equal [[0, :start_stream],
[0, :start_document],
[1, :start_sequence],
[2, :scalar],
[3, :scalar],
[3, :end_sequence],
[3, :end_document],
[3, :end_stream]], line_calls
assert_equal 3, @parser.mark.line
end
def test_column_numbers
assert_equal 0, @parser.mark.column
@parser.parse "---\n- hello\n- world"
col_calls = @handler.marks.map(&:column).zip(@handler.calls.map(&:first))
assert_equal [[0, :start_stream],
[3, :start_document],
[1, :start_sequence],
[0, :scalar],
[0, :scalar],
[0, :end_sequence],
[0, :end_document],
[0, :end_stream]], col_calls
assert_equal 0, @parser.mark.column
end
def test_index_numbers
assert_equal 0, @parser.mark.index
@parser.parse "---\n- hello\n- world"
idx_calls = @handler.marks.map(&:index).zip(@handler.calls.map(&:first))
assert_equal [[0, :start_stream],
[3, :start_document],
[5, :start_sequence],
[12, :scalar],
[19, :scalar],
[19, :end_sequence],
[19, :end_document],
[19, :end_stream]], idx_calls
assert_equal 19, @parser.mark.index
end
def test_bom
tadpole = 'おたまじゃくし'
# BOM + text
yml = "\uFEFF#{tadpole}".encode('UTF-16LE')
@parser.parse yml
assert_equal tadpole, @parser.handler.calls[2][1].first
end
def test_external_encoding
tadpole = 'おたまじゃくし'
@parser.external_encoding = Psych::Parser::UTF16LE
@parser.parse tadpole.encode 'UTF-16LE'
assert_equal tadpole, @parser.handler.calls[2][1].first
end
def test_bogus_io
o = Object.new
def o.external_encoding; nil end
def o.read len; self end
assert_raises(TypeError) do
@parser.parse o
end
end
def test_parse_io
@parser.parse StringIO.new("--- a")
assert_called :start_stream
assert_called :scalar
assert_called :end_stream
end
def test_syntax_error
assert_raises(Psych::SyntaxError) do
@parser.parse("---\n\"foo\"\n\"bar\"\n")
end
end
def test_syntax_error_twice
assert_raises(Psych::SyntaxError) do
@parser.parse("---\n\"foo\"\n\"bar\"\n")
end
assert_raises(Psych::SyntaxError) do
@parser.parse("---\n\"foo\"\n\"bar\"\n")
end
end
def test_syntax_error_has_path_for_string
e = assert_raises(Psych::SyntaxError) do
@parser.parse("---\n\"foo\"\n\"bar\"\n")
end
assert_match '(<unknown>):', e.message
end
def test_syntax_error_has_path_for_io
io = StringIO.new "---\n\"foo\"\n\"bar\"\n"
def io.path; "hello!"; end
e = assert_raises(Psych::SyntaxError) do
@parser.parse(io)
end
assert_match "(#{io.path}):", e.message
end
def test_mapping_end
@parser.parse("---\n!!map { key: value }")
assert_called :end_mapping
end
def test_mapping_tag
@parser.parse("---\n!!map { key: value }")
assert_called :start_mapping, ["tag:yaml.org,2002:map", false, Nodes::Mapping::FLOW]
end
def test_mapping_anchor
@parser.parse("---\n&A { key: value }")
assert_called :start_mapping, ['A', true, Nodes::Mapping::FLOW]
end
def test_mapping_block
@parser.parse("---\n key: value")
assert_called :start_mapping, [true, Nodes::Mapping::BLOCK]
end
def test_mapping_start
@parser.parse("---\n{ key: value }")
assert_called :start_mapping
assert_called :start_mapping, [true, Nodes::Mapping::FLOW]
end
def test_sequence_end
@parser.parse("---\n&A [1, 2]")
assert_called :end_sequence
end
def test_sequence_start_anchor
@parser.parse("---\n&A [1, 2]")
assert_called :start_sequence, ["A", true, Nodes::Sequence::FLOW]
end
def test_sequence_start_tag
@parser.parse("---\n!!seq [1, 2]")
assert_called :start_sequence, ["tag:yaml.org,2002:seq", false, Nodes::Sequence::FLOW]
end
def test_sequence_start_flow
@parser.parse("---\n[1, 2]")
assert_called :start_sequence, [true, Nodes::Sequence::FLOW]
end
def test_sequence_start_block
@parser.parse("---\n - 1\n - 2")
assert_called :start_sequence, [true, Nodes::Sequence::BLOCK]
end
def test_literal_scalar
@parser.parse(<<-eoyml)
%YAML 1.1
---
"literal\n\
\ttext\n"
eoyml
assert_called :scalar, ['literal text ', false, true, Nodes::Scalar::DOUBLE_QUOTED]
end
def test_scalar
@parser.parse("--- foo\n")
assert_called :scalar, ['foo', true, false, Nodes::Scalar::PLAIN]
end
def test_scalar_with_tag
@parser.parse("---\n!!str foo\n")
assert_called :scalar, ['foo', 'tag:yaml.org,2002:str', false, false, Nodes::Scalar::PLAIN]
end
def test_scalar_with_anchor
@parser.parse("---\n&A foo\n")
assert_called :scalar, ['foo', 'A', true, false, Nodes::Scalar::PLAIN]
end
def test_scalar_plain_implicit
@parser.parse("---\n&A foo\n")
assert_called :scalar, ['foo', 'A', true, false, Nodes::Scalar::PLAIN]
end
def test_alias
@parser.parse(<<-eoyml)
%YAML 1.1
---
!!seq [
!!str "Without properties",
&A !!str "Anchored",
!!str "Tagged",
*A,
!!str "",
]
eoyml
assert_called :alias, ['A']
end
def test_end_stream
@parser.parse("--- foo\n")
assert_called :end_stream
end
def test_start_stream
@parser.parse("--- foo\n")
assert_called :start_stream
end
def test_end_document_implicit
@parser.parse("\"foo\"\n")
assert_called :end_document, [true]
end
def test_end_document_explicit
@parser.parse("\"foo\"\n...")
assert_called :end_document, [false]
end
def test_start_document_version
@parser.parse("%YAML 1.1\n---\n\"foo\"\n")
assert_called :start_document, [[1,1], [], false]
end
def test_start_document_tag
@parser.parse("%TAG !yaml! tag:yaml.org,2002\n---\n!yaml!str \"foo\"\n")
assert_called :start_document, [[], [['!yaml!', 'tag:yaml.org,2002']], false]
end
def assert_called call, with = nil, parser = @parser
if with
call = parser.handler.calls.find { |x|
x.first == call && x.last.compact == with
}
assert(call,
"#{[call,with].inspect} not in #{parser.handler.calls.inspect}"
)
else
assert parser.handler.calls.any? { |x| x.first == call }
end
end
end
end