summaryrefslogtreecommitdiff
path: root/test/net/protocol/test_protocol.rb
blob: 2f42fa3236705abe727dea5c61e356dac13ff91a (plain)
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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# frozen_string_literal: true
require "test/unit"
require "net/protocol"
require "stringio"

class TestProtocol < Test::Unit::TestCase
  def test_should_properly_dot_stuff_period_with_no_endline
    bug9627 = '[ruby-core:61441] [Bug #9627]'
    sio = StringIO.new("".dup)
    imio = Net::InternetMessageIO.new(sio)
    email = "To: bob@aol.com\nlook, a period with no endline\n."
    imio.write_message(email)
    assert_equal("To: bob@aol.com\r\nlook, a period with no endline\r\n..\r\n.\r\n", sio.string, bug9627)
  end

  def test_each_crlf_line
    assert_output('', '') do
      sio = StringIO.new("".dup)
      imio = Net::InternetMessageIO.new(sio)
      assert_equal(23, imio.write_message("\u3042\r\u3044\n\u3046\r\n\u3048"))
      assert_equal("\u3042\r\n\u3044\r\n\u3046\r\n\u3048\r\n.\r\n", sio.string)

      sio = StringIO.new("".dup)
      imio = Net::InternetMessageIO.new(sio)
      assert_equal(8, imio.write_message("\u3042\r"))
      assert_equal("\u3042\r\n.\r\n", sio.string)
    end
  end

  def create_mockio(capacity: 100, max: nil)
    mockio = Object.new
    mockio.instance_variable_set(:@str, +'')
    mockio.instance_variable_set(:@capacity, capacity)
    mockio.instance_variable_set(:@max, max)
    def mockio.string; @str; end
    def mockio.to_io; self; end
    def mockio.wait_writable(sec); sleep sec; false; end
    def mockio.write_nonblock(*strs, exception: true)
      if @capacity <= @str.bytesize
        if exception
          raise Net::WaitWritable
        else
          return :wait_writable
        end
      end
      len = 0
      max = @max ? [@capacity, @str.bytesize + @max].min : @capacity
      strs.each do |str|
        len1 = @str.bytesize
        break if max <= len1
        @str << str.byteslice(0, max - @str.bytesize)
        len2 = @str.bytesize
        len += len2 - len1
      end
      len
    end
    mockio
  end

  def test_readuntil
    assert_output("", "") do
      sio = StringIO.new("12345".dup)
      io = Net::BufferedIO.new(sio)
      assert_equal "12345", io.readuntil("5")
    end
  end

  def test_write0_multibyte
    mockio = create_mockio(max: 1)
    io = Net::BufferedIO.new(mockio)
    assert_equal(3, io.write("\u3042"))
  end

  def test_write0_timeout
    mockio = create_mockio
    io = Net::BufferedIO.new(mockio)
    io.write_timeout = 0.1
    assert_raise(Net::WriteTimeout){ io.write("a"*1000) }
  end

  def test_write0_success
    mockio = create_mockio
    io = Net::BufferedIO.new(mockio)
    io.write_timeout = 0.1
    len = io.write("a"*10)
    assert_equal "a"*10, mockio.string
    assert_equal 10, len
  end

  def test_write0_success2
    mockio = create_mockio
    io = Net::BufferedIO.new(mockio)
    io.write_timeout = 0.1
    len = io.write("a"*100)
    assert_equal "a"*100, mockio.string
    assert_equal 100, len
  end

  def test_write0_success_multi1
    mockio = create_mockio
    io = Net::BufferedIO.new(mockio)
    io.write_timeout = 0.1
    len = io.write("a"*50, "a"*49)
    assert_equal "a"*99, mockio.string
    assert_equal 99, len
  end

  def test_write0_success_multi2
    mockio = create_mockio
    io = Net::BufferedIO.new(mockio)
    io.write_timeout = 0.1
    len = io.write("a"*50, "a"*50)
    assert_equal "a"*100, mockio.string
    assert_equal 100, len
  end

  def test_write0_timeout_multi1
    mockio = create_mockio
    io = Net::BufferedIO.new(mockio)
    io.write_timeout = 0.1
    assert_raise(Net::WriteTimeout){ io.write("a"*50,"a"*51) }
  end

  def test_write0_timeout_multi2
    mockio = create_mockio
    io = Net::BufferedIO.new(mockio)
    io.write_timeout = 0.1
    assert_raise(Net::WriteTimeout){ io.write("a"*50,"a"*50,"a") }
  end

  class FakeReadPartialIO
    def initialize(chunks)
      @chunks = chunks.map(&:dup)
    end

    def read_nonblock(size, buf = nil, exception: false)
      if buf
        buf.replace(@chunks.shift)
        buf
      else
        @chunks.shift
      end
    end
  end

  def test_shareable_buffer_leak # https://github.com/ruby/net-protocol/pull/19
    expected_chunks = [
      "aaaaa",
      "bbbbb",
    ]
    fake_io = FakeReadPartialIO.new(expected_chunks)
    io = Net::BufferedIO.new(fake_io)
    actual_chunks = []
    reader = Net::ReadAdapter.new(-> (chunk) { actual_chunks << chunk })
    io.read(5, reader)
    io.read(5, reader)
    assert_equal expected_chunks, actual_chunks
  end
end