summaryrefslogtreecommitdiff
path: root/spec/ruby/core/io/pread_spec.rb
blob: 6d93b432c2636d4e62a18fef3d61bda5451d67cd (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
# -*- encoding: utf-8 -*-
require_relative '../../spec_helper'

guard -> { platform_is_not :windows or ruby_version_is "3.3" } do
  describe "IO#pread" do
    before :each do
      @fname = tmp("io_pread.txt")
      @contents = "1234567890"
      touch(@fname) { |f| f.write @contents }
      @file = File.open(@fname, "r+")
    end

    after :each do
      @file.close
      rm_r @fname
    end

    it "accepts a length, and an offset" do
      @file.pread(4, 0).should == "1234"
      @file.pread(3, 4).should == "567"
    end

    it "accepts a length, an offset, and an output buffer" do
      buffer = +"foo"
      @file.pread(3, 4, buffer).should.equal?(buffer)
      buffer.should == "567"
    end

    it "shrinks the buffer in case of less bytes read" do
      buffer = +"foo"
      @file.pread(1, 0, buffer)
      buffer.should == "1"
    end

    it "grows the buffer in case of more bytes read" do
      buffer = +"foo"
      @file.pread(5, 0, buffer)
      buffer.should == "12345"
    end

    it "preserves the encoding of the given buffer" do
      buffer = ''.encode(Encoding::ISO_8859_1)
      @file.pread(10, 0, buffer)

      buffer.encoding.should == Encoding::ISO_8859_1
    end

    it "does not advance the file pointer" do
      @file.pread(4, 0).should == "1234"
      @file.read.should == "1234567890"
    end

    it "ignores the current offset" do
      @file.pos = 3
      @file.pread(4, 0).should == "1234"
    end

    it "returns an empty string for maxlen = 0" do
      @file.pread(0, 4).should == ""
    end

    it "ignores the offset for maxlen = 0, even if it is out of file bounds" do
      @file.pread(0, 400).should == ""
    end

    it "does not reset the buffer when reading with maxlen = 0" do
      buffer = +"foo"
      @file.pread(0, 4, buffer)
      buffer.should == "foo"

      @file.pread(0, 400, buffer)
      buffer.should == "foo"
    end

    it "converts maxlen to Integer using #to_int" do
      maxlen = mock('maxlen')
      maxlen.should_receive(:to_int).and_return(4)
      @file.pread(maxlen, 0).should == "1234"
    end

    it "converts offset to Integer using #to_int" do
      offset = mock('offset')
      offset.should_receive(:to_int).and_return(0)
      @file.pread(4, offset).should == "1234"
    end

    it "converts a buffer to String using to_str" do
      buffer = mock('buffer')
      buffer.should_receive(:to_str).at_least(1).and_return(+"foo")
      @file.pread(4, 0, buffer)
      buffer.should_not.is_a?(String)
      buffer.to_str.should == "1234"
    end

    it "raises TypeError if maxlen is not an Integer and cannot be coerced into Integer" do
      maxlen = Object.new
      -> { @file.pread(maxlen, 0) }.should raise_error(TypeError, 'no implicit conversion of Object into Integer')
    end

    it "raises TypeError if offset is not an Integer and cannot be coerced into Integer" do
      offset = Object.new
      -> { @file.pread(4, offset) }.should raise_error(TypeError, 'no implicit conversion of Object into Integer')
    end

    it "raises ArgumentError for negative values of maxlen" do
      -> { @file.pread(-4, 0) }.should raise_error(ArgumentError, 'negative string size (or size too big)')
    end

    it "raised Errno::EINVAL for negative values of offset" do
      -> { @file.pread(4, -1) }.should raise_error(Errno::EINVAL, /Invalid argument/)
    end

    it "raises TypeError if the buffer is not a String and cannot be coerced into String" do
      buffer = Object.new
      -> { @file.pread(4, 0, buffer) }.should raise_error(TypeError, 'no implicit conversion of Object into String')
    end

    it "raises EOFError if end-of-file is reached" do
      -> { @file.pread(1, 10) }.should raise_error(EOFError)
    end

    it "raises IOError when file is not open in read mode" do
      File.open(@fname, "w") do |file|
        -> { file.pread(1, 1) }.should raise_error(IOError)
      end
    end

    it "raises IOError when file is closed" do
      file = File.open(@fname, "r+")
      file.close
      -> { file.pread(1, 1) }.should raise_error(IOError)
    end
  end
end