333 lines
8.3 KiB
Ruby
333 lines
8.3 KiB
Ruby
|
require 'em_test_helper'
|
||
|
|
||
|
# TODO!!! Need tests for overlength headers and text bodies.
|
||
|
|
||
|
class TestLineText2 < Test::Unit::TestCase
|
||
|
|
||
|
# Run each of these tests two ways: passing in the whole test-dataset in one chunk,
|
||
|
# and passing it in one character at a time.
|
||
|
|
||
|
class Basic
|
||
|
include EM::Protocols::LineText2
|
||
|
attr_reader :lines
|
||
|
def receive_line line
|
||
|
(@lines ||= []) << line
|
||
|
end
|
||
|
end
|
||
|
def test_basic
|
||
|
testdata = "Line 1\nLine 2\r\nLine 3\n"
|
||
|
|
||
|
a = Basic.new
|
||
|
a.receive_data testdata
|
||
|
assert_equal( ["Line 1", "Line 2", "Line 3"], a.lines )
|
||
|
|
||
|
a = Basic.new
|
||
|
testdata.length.times {|i| a.receive_data( testdata[i...i+1] ) }
|
||
|
assert_equal( ["Line 1", "Line 2", "Line 3"], a.lines )
|
||
|
end
|
||
|
|
||
|
# The basic test above shows that extra newlines are chomped
|
||
|
# This test shows that newlines are preserved if the delimiter isn't \n
|
||
|
class PreserveNewlines
|
||
|
include EM::Protocols::LineText2
|
||
|
attr_reader :lines
|
||
|
def initialize *args
|
||
|
super
|
||
|
@delim = "|"
|
||
|
set_delimiter @delim
|
||
|
end
|
||
|
def receive_line line
|
||
|
(@lines ||= []) << line
|
||
|
end
|
||
|
end
|
||
|
def test_preserve_newlines
|
||
|
a = PreserveNewlines.new
|
||
|
a.receive_data "aaa|bbb|ccc|\n|\r\n| \t ||"
|
||
|
assert_equal( ["aaa", "bbb", "ccc", "\n", "\r\n", " \t ", ""], a.lines )
|
||
|
end
|
||
|
|
||
|
class ChangeDelimiter
|
||
|
include EM::Protocols::LineText2
|
||
|
attr_reader :lines
|
||
|
def initialize *args
|
||
|
super
|
||
|
@delim = "A"
|
||
|
set_delimiter @delim
|
||
|
end
|
||
|
def receive_line line
|
||
|
(@lines ||= []) << line
|
||
|
set_delimiter( @delim.succ! )
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def test_change_delimiter
|
||
|
testdata = %Q(LineaALinebBLinecCLinedD)
|
||
|
|
||
|
a = ChangeDelimiter.new
|
||
|
a.receive_data testdata
|
||
|
assert_equal( ["Linea", "Lineb", "Linec", "Lined"], a.lines )
|
||
|
|
||
|
a = ChangeDelimiter.new
|
||
|
testdata.length.times {|i| a.receive_data( testdata[i...i+1] ) }
|
||
|
assert_equal( ["Linea", "Lineb", "Linec", "Lined"], a.lines )
|
||
|
end
|
||
|
|
||
|
class RegexDelimiter
|
||
|
include EM::Protocols::LineText2
|
||
|
attr_reader :lines
|
||
|
def initialize *args
|
||
|
super
|
||
|
@delim = /[A-D]/
|
||
|
set_delimiter @delim
|
||
|
end
|
||
|
def receive_line line
|
||
|
(@lines ||= []) << line
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def test_regex_delimiter
|
||
|
testdata = %Q(LineaALinebBLinecCLinedD)
|
||
|
|
||
|
a = RegexDelimiter.new
|
||
|
a.receive_data testdata
|
||
|
assert_equal( ["Linea", "Lineb", "Linec", "Lined"], a.lines )
|
||
|
|
||
|
a = RegexDelimiter.new
|
||
|
testdata.length.times {|i| a.receive_data( testdata[i...i+1] ) }
|
||
|
assert_equal( ["Linea", "Lineb", "Linec", "Lined"], a.lines )
|
||
|
end
|
||
|
|
||
|
#--
|
||
|
# Test two lines followed by an empty line, ten bytes of binary data, then
|
||
|
# two more lines.
|
||
|
|
||
|
class Binary
|
||
|
include EM::Protocols::LineText2
|
||
|
attr_reader :lines, :body
|
||
|
def initialize *args
|
||
|
super
|
||
|
@lines = []
|
||
|
@body = nil
|
||
|
end
|
||
|
def receive_line ln
|
||
|
if ln == ""
|
||
|
set_text_mode 10
|
||
|
else
|
||
|
@lines << ln
|
||
|
end
|
||
|
end
|
||
|
def receive_binary_data data
|
||
|
@body = data
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def test_binary
|
||
|
testdata = %Q(Line 1
|
||
|
Line 2
|
||
|
|
||
|
0000000000Line 3
|
||
|
Line 4
|
||
|
)
|
||
|
|
||
|
a = Binary.new
|
||
|
a.receive_data testdata
|
||
|
assert_equal( ["Line 1", "Line 2", "Line 3", "Line 4"], a.lines)
|
||
|
assert_equal( "0000000000", a.body )
|
||
|
|
||
|
a = Binary.new
|
||
|
testdata.length.times {|i| a.receive_data( testdata[i...i+1] ) }
|
||
|
assert_equal( ["Line 1", "Line 2", "Line 3", "Line 4"], a.lines)
|
||
|
assert_equal( "0000000000", a.body )
|
||
|
end
|
||
|
|
||
|
|
||
|
# Test unsized binary data. The expectation is that each chunk of it
|
||
|
# will be passed to us as it it received.
|
||
|
class UnsizedBinary
|
||
|
include EM::Protocols::LineText2
|
||
|
attr_reader :n_calls, :body
|
||
|
def initialize *args
|
||
|
super
|
||
|
set_text_mode
|
||
|
end
|
||
|
def receive_binary_data data
|
||
|
@n_calls ||= 0
|
||
|
@n_calls += 1
|
||
|
(@body ||= "") << data
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def test_unsized_binary
|
||
|
testdata = "X\0" * 1000
|
||
|
|
||
|
a = UnsizedBinary.new
|
||
|
a.receive_data testdata
|
||
|
assert_equal( 1, a.n_calls )
|
||
|
assert_equal( testdata, a.body )
|
||
|
|
||
|
a = UnsizedBinary.new
|
||
|
testdata.length.times {|i| a.receive_data( testdata[i...i+1] ) }
|
||
|
assert_equal( 2000, a.n_calls )
|
||
|
assert_equal( testdata, a.body )
|
||
|
end
|
||
|
|
||
|
|
||
|
# Test binary data with a "throw back" into line-mode.
|
||
|
class ThrowBack
|
||
|
include EM::Protocols::LineText2
|
||
|
attr_reader :headers
|
||
|
def initialize *args
|
||
|
super
|
||
|
@headers = []
|
||
|
@n_bytes = 0
|
||
|
set_text_mode
|
||
|
end
|
||
|
def receive_binary_data data
|
||
|
wanted = 25 - @n_bytes
|
||
|
will_take = if data.length > wanted
|
||
|
data.length - wanted
|
||
|
else
|
||
|
data.length
|
||
|
end
|
||
|
@n_bytes += will_take
|
||
|
|
||
|
if @n_bytes == 25
|
||
|
set_line_mode( data[will_take..-1] )
|
||
|
end
|
||
|
end
|
||
|
def receive_line ln
|
||
|
@headers << ln
|
||
|
end
|
||
|
end
|
||
|
def test_throw_back
|
||
|
testdata = "Line\n" * 10
|
||
|
|
||
|
a = ThrowBack.new
|
||
|
a.receive_data testdata
|
||
|
assert_equal( ["Line"] * 5, a.headers )
|
||
|
|
||
|
a = ThrowBack.new
|
||
|
testdata.length.times {|i| a.receive_data( testdata[i...i+1] ) }
|
||
|
assert_equal( ["Line"] * 5, a.headers )
|
||
|
end
|
||
|
|
||
|
# Test multi-character line delimiters.
|
||
|
# Also note that the test data has a "tail" with no delimiter, that will be
|
||
|
# discarded, but cf. the BinaryTail test.
|
||
|
# TODO!!! This test doesn't work in the byte-by-byte case.
|
||
|
class Multichar
|
||
|
include EM::Protocols::LineText2
|
||
|
attr_reader :lines
|
||
|
def initialize *args
|
||
|
super
|
||
|
@lines = []
|
||
|
set_delimiter "012"
|
||
|
end
|
||
|
def receive_line ln
|
||
|
@lines << ln
|
||
|
end
|
||
|
end
|
||
|
def test_multichar
|
||
|
testdata = "Line012Line012Line012Line"
|
||
|
|
||
|
a = Multichar.new
|
||
|
a.receive_data testdata
|
||
|
assert_equal( ["Line"]*3, a.lines )
|
||
|
|
||
|
a = Multichar.new
|
||
|
testdata.length.times {|i| a.receive_data( testdata[i...i+1] ) }
|
||
|
# DOESN'T WORK in this case. Multi-character delimiters are broken.
|
||
|
#assert_equal( ["Line"]*3, a.lines )
|
||
|
end
|
||
|
|
||
|
# Test a binary "tail," when a sized binary transfer doesn't complete because
|
||
|
# of an unbind. We get a partial result.
|
||
|
class BinaryTail
|
||
|
include EM::Protocols::LineText2
|
||
|
attr_reader :data
|
||
|
def initialize *args
|
||
|
super
|
||
|
@data = ""
|
||
|
set_text_mode 1000
|
||
|
end
|
||
|
def receive_binary_data data
|
||
|
# we expect to get all the data in one chunk, even in the byte-by-byte case,
|
||
|
# because sized transfers by definition give us exactly one call to
|
||
|
# #receive_binary_data.
|
||
|
@data = data
|
||
|
end
|
||
|
end
|
||
|
def test_binary_tail
|
||
|
testdata = "0" * 500
|
||
|
|
||
|
a = BinaryTail.new
|
||
|
a.receive_data testdata
|
||
|
a.unbind
|
||
|
assert_equal( "0" * 500, a.data )
|
||
|
|
||
|
a = BinaryTail.new
|
||
|
testdata.length.times {|i| a.receive_data( testdata[i...i+1] ) }
|
||
|
a.unbind
|
||
|
assert_equal( "0" * 500, a.data )
|
||
|
end
|
||
|
|
||
|
|
||
|
# Test an end-of-binary call. Arrange to receive binary data but don't bother counting it
|
||
|
# as it comes. Rely on getting receive_end_of_binary_data to signal the transition back to
|
||
|
# line mode.
|
||
|
# At the present time, this isn't strictly necessary with sized binary chunks because by
|
||
|
# definition we accumulate them and make exactly one call to receive_binary_data, but
|
||
|
# we may want to support a mode in the future that would break up large chunks into multiple
|
||
|
# calls.
|
||
|
class LazyBinary
|
||
|
include EM::Protocols::LineText2
|
||
|
attr_reader :data, :end
|
||
|
def initialize *args
|
||
|
super
|
||
|
@data = ""
|
||
|
set_text_mode 1000
|
||
|
end
|
||
|
def receive_binary_data data
|
||
|
# we expect to get all the data in one chunk, even in the byte-by-byte case,
|
||
|
# because sized transfers by definition give us exactly one call to
|
||
|
# #receive_binary_data.
|
||
|
@data = data
|
||
|
end
|
||
|
def receive_end_of_binary_data
|
||
|
@end = true
|
||
|
end
|
||
|
end
|
||
|
def test_receive_end_of_binary_data
|
||
|
testdata = "_" * 1000
|
||
|
a = LazyBinary.new
|
||
|
testdata.length.times {|i| a.receive_data( testdata[i...i+1] ) }
|
||
|
assert_equal( "_" * 1000, a.data )
|
||
|
assert( a.end )
|
||
|
end
|
||
|
|
||
|
|
||
|
# This tests a bug fix in which calling set_text_mode failed when called
|
||
|
# inside receive_binary_data.
|
||
|
#
|
||
|
class BinaryPair
|
||
|
include EM::Protocols::LineText2
|
||
|
attr_reader :sizes
|
||
|
def initialize *args
|
||
|
super
|
||
|
set_text_mode 1
|
||
|
@sizes = []
|
||
|
end
|
||
|
def receive_binary_data dt
|
||
|
@sizes << dt.length
|
||
|
set_text_mode( (dt.length == 1) ? 2 : 1 )
|
||
|
end
|
||
|
end
|
||
|
def test_binary_pairs
|
||
|
test_data = "123" * 5
|
||
|
a = BinaryPair.new
|
||
|
a.receive_data test_data
|
||
|
assert_equal( [1,2,1,2,1,2,1,2,1,2], a.sizes )
|
||
|
end
|
||
|
|
||
|
end
|