minitar 0.12.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/minitar.rb CHANGED
@@ -1,12 +1,300 @@
1
- # coding: utf-8
1
+ require "fileutils"
2
+ require "rbconfig"
2
3
 
3
- require "archive/tar/minitar"
4
+ # == Synopsis
5
+ #
6
+ # Using minitar is easy. The simplest case is:
7
+ #
8
+ # require 'zlib'
9
+ # require 'minitar'
10
+ #
11
+ # # Packs everything that matches Find.find('tests').
12
+ # # test.tar will automatically be closed by Minitar.pack.
13
+ # Minitar.pack('tests', File.open('test.tar', 'wb'))
14
+ #
15
+ # # Unpacks 'test.tar' to 'x', creating 'x' if necessary.
16
+ # Minitar.unpack('test.tar', 'x')
17
+ #
18
+ # A gzipped tar can be written with:
19
+ #
20
+ # # test.tgz will be closed automatically.
21
+ # Minitar.pack('tests', Zlib::GzipWriter.new(File.open('test.tgz', 'wb'))
22
+ #
23
+ # # test.tgz will be closed automatically.
24
+ # Minitar.unpack(Zlib::GzipReader.new(File.open('test.tgz', 'rb')), 'x')
25
+ #
26
+ # As the case above shows, one need not write to a file. However, it will
27
+ # sometimes require that one dive a little deeper into the API, as in the case
28
+ # of StringIO objects. Note that I'm not providing a block with
29
+ # Minitar::Output, as Minitar::Output#close automatically closes both the
30
+ # Output object and the wrapped data stream object.
31
+ #
32
+ # begin
33
+ # sgz = Zlib::GzipWriter.new(StringIO.new(""))
34
+ # tar = Output.new(sgz)
35
+ # Find.find('tests') do |entry|
36
+ # Minitar.pack_file(entry, tar)
37
+ # end
38
+ # ensure
39
+ # # Closes both tar and sgz.
40
+ # tar.close
41
+ # end
42
+ class Minitar
43
+ VERSION = "1.0.0".freeze # :nodoc:
4
44
 
5
- if defined?(::Minitar) && ::Minitar != Archive::Tar::Minitar
6
- warn <<-EOS
7
- ::Minitar is already defined.
8
- This will conflict with future versions of minitar.
9
- EOS
10
- else
11
- ::Minitar = Archive::Tar::Minitar
45
+ # The base class for any minitar error.
46
+ Error = Class.new(::StandardError)
47
+ # Raised when a wrapped data stream class is not seekable.
48
+ NonSeekableStream = Class.new(Error)
49
+ # The exception raised when operations are performed on a stream that has
50
+ # previously been closed.
51
+ ClosedStream = Class.new(Error)
52
+ # The exception raised when a filename exceeds 256 bytes in length, the
53
+ # maximum supported by the standard Tar format.
54
+ FileNameTooLong = Class.new(Error)
55
+ # The exception raised when a data stream ends before the amount of data
56
+ # expected in the archive's PosixHeader.
57
+ UnexpectedEOF = Class.new(StandardError)
58
+ # The exception raised when a file contains a relative path in secure mode
59
+ # (the default for this version).
60
+ SecureRelativePathError = Class.new(Error)
61
+ # The exception raised when a file contains an invalid Posix header.
62
+ InvalidTarStream = Class.new(Error)
12
63
  end
64
+
65
+ class << Minitar
66
+ # Tests if +path+ refers to a directory. Fixes an apparently
67
+ # corrupted <tt>stat()</tt> call on Windows.
68
+ def dir?(path)
69
+ File.directory?((path[-1] == "/") ? path : "#{path}/")
70
+ end
71
+
72
+ # A convenience method for wrapping Minitar::Input.open
73
+ # (mode +r+) and Minitar::Output.open (mode +w+). No other
74
+ # modes are currently supported.
75
+ def open(dest, mode = "r", &)
76
+ case mode
77
+ when "r"
78
+ Input.open(dest, &)
79
+ when "w"
80
+ Output.open(dest, &block)
81
+ else
82
+ raise "Unknown open mode for Minitar.open."
83
+ end
84
+ end
85
+
86
+ def const_missing(c) # :nodoc:
87
+ case c
88
+ when :BlockRequired
89
+ warn "This constant has been removed."
90
+ const_set(:BlockRequired, Class.new(StandardError))
91
+ else
92
+ super
93
+ end
94
+ end
95
+
96
+ def windows? # :nodoc:
97
+ RbConfig::CONFIG["host_os"] =~ /^(mswin|mingw|cygwin)/
98
+ end
99
+
100
+ # A convenience method to pack the provided +data+ as a file named +entry+. +entry+ may
101
+ # either be a name or a Hash with the fields described below. When only a name is
102
+ # provided, or only some Hash fields are provided, the default values will apply.
103
+ #
104
+ # <tt>:name</tt>:: The filename to be packed into the archive. Required.
105
+ # <tt>:mode</tt>:: The mode to be applied. Defaults to 0o644 for files and 0o755 for
106
+ # directories.
107
+ # <tt>:uid</tt>:: The user owner of the file. Default is +nil+.
108
+ # <tt>:gid</tt>:: The group owner of the file. Default is +nil+.
109
+ # <tt>:mtime</tt>:: The modification Time of the file. Default is +Time.now+.
110
+ #
111
+ # If +data+ is +nil+, a directory will be created. Use an empty String for a normal
112
+ # empty file.
113
+ def pack_as_file(entry, data, outputter) # :yields action, name, stats:
114
+ if outputter.is_a?(Minitar::Output)
115
+ outputter = outputter.tar
116
+ end
117
+
118
+ stats = {
119
+ gid: nil,
120
+ uid: nil,
121
+ mtime: Time.now,
122
+ size: data&.size || 0,
123
+ mode: data ? 0o644 : 0o755
124
+ }
125
+
126
+ if entry.is_a?(Hash)
127
+ name = entry.delete(:name)
128
+ entry.each_pair { stats[_1] = _2 unless _2.nil? }
129
+ else
130
+ name = entry
131
+ end
132
+
133
+ if data.nil? # Create a directory
134
+ yield :dir, name, stats if block_given?
135
+ outputter.mkdir(name, stats)
136
+ else
137
+ outputter.add_file_simple(name, stats) do |os|
138
+ stats[:current] = 0
139
+ yield :file_start, name, stats if block_given?
140
+
141
+ StringIO.open(data, "rb") do |ff|
142
+ until ff.eof?
143
+ stats[:currinc] = os.write(ff.read(4096))
144
+ stats[:current] += stats[:currinc]
145
+ yield :file_progress, name, stats if block_given?
146
+ end
147
+ end
148
+
149
+ yield :file_done, name, stats if block_given?
150
+ end
151
+ end
152
+ end
153
+
154
+ # A convenience method to pack the file provided. +entry+ may either be a filename (in
155
+ # which case various values for the file (see below) will be obtained from
156
+ # <tt>File#stat(entry)</tt> or a Hash with the fields:
157
+ #
158
+ # <tt>:name</tt>:: The filename to be packed into the archive. Required.
159
+ # <tt>:mode</tt>:: The mode to be applied.
160
+ # <tt>:uid</tt>:: The user owner of the file. (Ignored on Windows.)
161
+ # <tt>:gid</tt>:: The group owner of the file. (Ignored on Windows.)
162
+ # <tt>:mtime</tt>:: The modification Time of the file.
163
+ #
164
+ # During packing, if a block is provided, #pack_file yields an +action+ Symol, the
165
+ # full name of the file being packed, and a Hash of statistical information, just as
166
+ # with Minitar::Input#extract_entry.
167
+ #
168
+ # The +action+ will be one of:
169
+ # <tt>:dir</tt>:: The +entry+ is a directory.
170
+ # <tt>:file_start</tt>:: The +entry+ is a file; the extract of the
171
+ # file is just beginning.
172
+ # <tt>:file_progress</tt>:: Yielded every 4096 bytes during the extract
173
+ # of the +entry+.
174
+ # <tt>:file_done</tt>:: Yielded when the +entry+ is completed.
175
+ #
176
+ # The +stats+ hash contains the following keys:
177
+ # <tt>:current</tt>:: The current total number of bytes read in the
178
+ # +entry+.
179
+ # <tt>:currinc</tt>:: The current number of bytes read in this read
180
+ # cycle.
181
+ # <tt>:name</tt>:: The filename to be packed into the tarchive.
182
+ # *REQUIRED*.
183
+ # <tt>:mode</tt>:: The mode to be applied.
184
+ # <tt>:uid</tt>:: The user owner of the file. (+nil+ on Windows.)
185
+ # <tt>:gid</tt>:: The group owner of the file. (+nil+ on Windows.)
186
+ # <tt>:mtime</tt>:: The modification Time of the file.
187
+ def pack_file(entry, outputter) # :yields action, name, stats:
188
+ if outputter.is_a?(Minitar::Output)
189
+ outputter = outputter.tar
190
+ end
191
+
192
+ stats = {}
193
+
194
+ if entry.is_a?(Hash)
195
+ name = entry[:name]
196
+ entry.each { |kk, vv| stats[kk] = vv unless vv.nil? }
197
+ else
198
+ name = entry
199
+ end
200
+
201
+ name = name.sub(%r{\./}, "")
202
+ stat = File.stat(name)
203
+ stats[:mode] ||= stat.mode
204
+ stats[:mtime] ||= stat.mtime
205
+ stats[:size] = stat.size
206
+
207
+ if windows?
208
+ stats[:uid] = nil
209
+ stats[:gid] = nil
210
+ else
211
+ stats[:uid] ||= stat.uid
212
+ stats[:gid] ||= stat.gid
213
+ end
214
+
215
+ if File.file?(name)
216
+ outputter.add_file_simple(name, stats) do |os|
217
+ stats[:current] = 0
218
+ yield :file_start, name, stats if block_given?
219
+ File.open(name, "rb") do |ff|
220
+ until ff.eof?
221
+ stats[:currinc] = os.write(ff.read(4096))
222
+ stats[:current] += stats[:currinc]
223
+ yield :file_progress, name, stats if block_given?
224
+ end
225
+ end
226
+ yield :file_done, name, stats if block_given?
227
+ end
228
+ elsif dir?(name)
229
+ yield :dir, name, stats if block_given?
230
+ outputter.mkdir(name, stats)
231
+ else
232
+ raise "Don't yet know how to pack this type of file."
233
+ end
234
+ end
235
+
236
+ # A convenience method to pack files specified by +src+ into +dest+. If
237
+ # +src+ is an Array, then each file detailed therein will be packed into
238
+ # the resulting Minitar::Output stream; if +recurse_dirs+ is
239
+ # true, then directories will be recursed.
240
+ #
241
+ # If +src+ is not an Array, it will be treated as the result of Find.find;
242
+ # all files matching will be packed.
243
+ def pack(src, dest, recurse_dirs = true, &block)
244
+ require "find"
245
+ Minitar::Output.open(dest) do |outp|
246
+ if src.is_a?(Array)
247
+ src.each do |entry|
248
+ if dir?(entry) && recurse_dirs
249
+ Find.find(entry) do |ee|
250
+ pack_file(ee, outp, &block)
251
+ end
252
+ else
253
+ pack_file(entry, outp, &block)
254
+ end
255
+ end
256
+ else
257
+ Find.find(src) do |entry|
258
+ pack_file(entry, outp, &block)
259
+ end
260
+ end
261
+ end
262
+ end
263
+
264
+ # A convenience method to unpack files from +src+ into the directory
265
+ # specified by +dest+. Only those files named explicitly in +files+
266
+ # will be extracted.
267
+ def unpack(src, dest, files = [], options = {}, &block)
268
+ Minitar::Input.open(src) do |inp|
269
+ if File.exist?(dest) && !dir?(dest)
270
+ raise "Can't unpack to a non-directory."
271
+ end
272
+
273
+ FileUtils.mkdir_p(dest) unless File.exist?(dest)
274
+
275
+ inp.each do |entry|
276
+ if files.empty? || files.include?(entry.full_name)
277
+ inp.extract_entry(dest, entry, options, &block)
278
+ end
279
+ end
280
+ end
281
+ end
282
+
283
+ # Check whether +io+ can seek without errors.
284
+ def seekable?(io, methods = nil)
285
+ # The IO class throws an exception at runtime if we try to change
286
+ # position on a non-regular file.
287
+ if io.respond_to?(:stat)
288
+ io.stat.file?
289
+ else
290
+ # Duck-type the rest of this.
291
+ methods ||= [:pos, :pos=, :seek, :rewind]
292
+ methods = [methods] unless methods.is_a?(Array)
293
+ methods.all? { |m| io.respond_to?(m) }
294
+ end
295
+ end
296
+ end
297
+
298
+ require "minitar/posix_header"
299
+ require "minitar/input"
300
+ require "minitar/output"
@@ -1,5 +1,3 @@
1
- # frozen_string_literal: true
2
-
3
1
  require "fileutils"
4
2
  require "minitar"
5
3
 
@@ -1,13 +1,12 @@
1
- # frozen_string_literal: true
2
-
3
1
  module TarTestHelpers
4
- include Archive::Tar::Minitar::ByteSize
5
-
6
2
  Field = Struct.new(:name, :offset, :length)
7
3
  def self.Field(name, length)
4
+ # standard:disable ThreadSafety/InstanceVariableInClassMethod
8
5
  @offset ||= 0
9
6
  field = Field.new(name, @offset, length)
10
7
  @offset += length
8
+ # standard:enable ThreadSafety/InstanceVariableInClassMethod
9
+
11
10
  FIELDS[name] = field
12
11
  FIELD_ORDER << name
13
12
  field
@@ -51,7 +50,7 @@ module TarTestHelpers
51
50
  offset = FIELDS[field].offset
52
51
  length = FIELDS[field].length
53
52
 
54
- assert_equal(expected[offset, length], actual[offset, length], message)
53
+ assert_equal expected[offset, length], actual[offset, length], message
55
54
  end
56
55
  end
57
56
 
@@ -95,8 +94,8 @@ module TarTestHelpers
95
94
  ]
96
95
 
97
96
  h = arr.join.bytes.to_a.pack("C100C8C8C8C12C12C8CC100C6C2C32C32C8C8C155")
98
- ret = h + "\0" * (512 - bytesize(h))
99
- assert_equal(512, bytesize(ret))
97
+ ret = h + "\0" * (512 - h.bytesize)
98
+ assert_equal 512, ret.bytesize
100
99
  ret
101
100
  end
102
101
 
@@ -116,7 +115,7 @@ module TarTestHelpers
116
115
  end
117
116
 
118
117
  def asciiz(str, length)
119
- str + "\0" * (length - bytesize(str))
118
+ str + "\0" * (length - str.bytesize)
120
119
  end
121
120
 
122
121
  def sp(s)
@@ -0,0 +1,49 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "minitar"
4
+ require "minitest_helper"
5
+ require "base64"
6
+ require "zlib"
7
+
8
+ class TestIssue46 < Minitest::Test
9
+ SUPERLONG_TGZ = Base64.decode64(<<~EOS).freeze
10
+ H4sIAK1+smYAA+3WQQ6CMBAF0K49BScAprYd3XkALoECSiQlQYzXt0IkSKLGBdXE
11
+ /zbtNF000PkQRmG0SWq7T0p7FPOIHaNUNzrTkWI5zPt1IiYtgmSm8zw4n9q0CQLR
12
+ 1HX7at/lkOeVjwP5FZNcKm14tU63uyyPUP91/e3rCJ75uF/j/Gej+6yXw/fArbnM
13
+ Z2ZlDKlb/ktNrEQQ+3gA9/xP3aS0z/e5bUXh40B+/Vj+oJ63Xkzff26zoqzmzf13
14
+ /d/98437n0izQf8DAAAAAAAAAAAAAAAAAHziCqQuXDYAKAAA
15
+ EOS
16
+
17
+ FILETIMES = Time.utc(2004).to_i
18
+
19
+ superlong_name = (["0123456789abcde"] * 33).join("/")
20
+
21
+ SUPERLONG_CONTENTS = {
22
+ superlong_name => {size: 496, mode: 0o644},
23
+ "endfile" => {size: 0, mode: 0o644}
24
+ }
25
+
26
+ def test_each_works
27
+ reader = Zlib::GzipReader.new(StringIO.new(SUPERLONG_TGZ))
28
+
29
+ Minitar::Input.open(reader) do |stream|
30
+ outer = 0
31
+ stream.each.with_index do |entry, i|
32
+ assert_kind_of Minitar::Reader::EntryStream, entry
33
+ assert SUPERLONG_CONTENTS.key?(entry.name), "File #{entry.name} not defined"
34
+
35
+ assert_equal SUPERLONG_CONTENTS[entry.name][:size],
36
+ entry.size,
37
+ "File sizes sizes do not match: #{entry.name}"
38
+
39
+ assert_modes_equal(SUPERLONG_CONTENTS[entry.name][:mode],
40
+ entry.mode, entry.name)
41
+ assert_equal FILETIMES, entry.mtime, "entry.mtime"
42
+
43
+ outer += 1
44
+ end
45
+
46
+ assert_equal 2, outer
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,60 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "minitar"
4
+ require "minitest_helper"
5
+ require "zlib"
6
+
7
+ class TestMinitar < Minitest::Test
8
+ FILE_2004 = Time.utc(2004).to_i
9
+
10
+ def test_pack_as_file
11
+ input = [
12
+ ["path", nil],
13
+ ["test", "test"],
14
+ ["extra/test", "extra/test"],
15
+ [{name: "empty2004", mtime: FILE_2004, mode: 0o755}, ""]
16
+ ]
17
+
18
+ writer = StringIO.new
19
+ Minitar::Output.open(writer) do |out_stream|
20
+ input.each do |(name, data)|
21
+ Minitar.pack_as_file(name, data, out_stream)
22
+ end
23
+ end
24
+
25
+ expected = [
26
+ {name: "path", size: 0, mode: 0o755},
27
+ {name: "test", size: 4, mode: 0o644, data: "test"},
28
+ {name: "extra/test", size: 10, mode: 0o0644, data: "extra/test"},
29
+ {name: "empty2004", size: 0, mode: 0o755, mtime: FILE_2004, nil: true}
30
+ ]
31
+
32
+ count = 0
33
+ reader = StringIO.new(writer.string)
34
+ Minitar::Input.open(reader) do |stream|
35
+ stream.each.with_index do |entry, i|
36
+ assert_kind_of Minitar::Reader::EntryStream, entry
37
+
38
+ assert_equal expected[i][:name], entry.name
39
+ assert_equal expected[i][:size], entry.size
40
+ assert_equal expected[i][:mode], entry.mode
41
+
42
+ if expected[i].key?(:mtime)
43
+ assert_equal expected[i][:mtime], entry.mtime
44
+ end
45
+
46
+ if expected[i].key?(:data)
47
+ assert_equal expected[i][:data], entry.read
48
+ end
49
+
50
+ if expected[i].key?(:nil)
51
+ assert_nil entry.read
52
+ end
53
+
54
+ count += 1
55
+ end
56
+ end
57
+
58
+ assert_equal expected.size, count
59
+ end
60
+ end
@@ -1,81 +1,79 @@
1
- # frozen_string_literal: true
2
-
3
1
  require "minitest_helper"
4
2
 
5
3
  class TestTarHeader < Minitest::Test
6
4
  def test_arguments_are_checked
7
- ph = Archive::Tar::Minitar::PosixHeader
5
+ ph = Minitar::PosixHeader
8
6
  assert_raises(ArgumentError) {
9
- ph.new(:name => "", :size => "", :mode => "")
7
+ ph.new(name: "", size: "", mode: "")
10
8
  }
11
9
  assert_raises(ArgumentError) {
12
- ph.new(:name => "", :size => "", :prefix => "")
10
+ ph.new(name: "", size: "", prefix: "")
13
11
  }
14
12
  assert_raises(ArgumentError) {
15
- ph.new(:name => "", :prefix => "", :mode => "")
13
+ ph.new(name: "", prefix: "", mode: "")
16
14
  }
17
15
  assert_raises(ArgumentError) {
18
- ph.new(:prefix => "", :size => "", :mode => "")
16
+ ph.new(prefix: "", size: "", mode: "")
19
17
  }
20
18
  end
21
19
 
22
20
  def test_basic_headers
23
21
  header = {
24
- :name => "bla",
25
- :mode => 0o12345,
26
- :size => 10,
27
- :prefix => "",
28
- :typeflag => "0"
22
+ name: "bla",
23
+ mode: 0o12345,
24
+ size: 10,
25
+ prefix: "",
26
+ typeflag: "0"
29
27
  }
30
28
  assert_headers_equal(tar_file_header("bla", "", 0o12345, 10),
31
- Archive::Tar::Minitar::PosixHeader.new(header).to_s)
29
+ Minitar::PosixHeader.new(header).to_s)
32
30
 
33
31
  header = {
34
- :name => "bla",
35
- :mode => 0o12345,
36
- :size => 0,
37
- :prefix => "",
38
- :typeflag => "5"
32
+ name: "bla",
33
+ mode: 0o12345,
34
+ size: 0,
35
+ prefix: "",
36
+ typeflag: "5"
39
37
  }
40
38
  assert_headers_equal(tar_dir_header("bla", "", 0o12345),
41
- Archive::Tar::Minitar::PosixHeader.new(header).to_s)
39
+ Minitar::PosixHeader.new(header).to_s)
42
40
  end
43
41
 
44
42
  def test_long_name_works
45
43
  header = {
46
- :name => "a" * 100, :mode => 0o12345, :size => 10, :prefix => ""
44
+ name: "a" * 100, mode: 0o12345, size: 10, prefix: ""
47
45
  }
48
46
  assert_headers_equal(tar_file_header("a" * 100, "", 0o12345, 10),
49
- Archive::Tar::Minitar::PosixHeader.new(header).to_s)
47
+ Minitar::PosixHeader.new(header).to_s)
50
48
  header = {
51
- :name => "a" * 100, :mode => 0o12345, :size => 10, :prefix => "bb" * 60
49
+ name: "a" * 100, mode: 0o12345, size: 10, prefix: "bb" * 60
52
50
  }
53
51
  assert_headers_equal(tar_file_header("a" * 100, "bb" * 60, 0o12345, 10),
54
- Archive::Tar::Minitar::PosixHeader.new(header).to_s)
52
+ Minitar::PosixHeader.new(header).to_s)
55
53
  end
56
54
 
57
55
  def test_from_stream
58
56
  header = tar_file_header("a" * 100, "", 0o12345, 10)
59
57
  header = StringIO.new(header)
60
- h = Archive::Tar::Minitar::PosixHeader.from_stream(header)
61
- assert_equal("a" * 100, h.name)
62
- assert_equal(0o12345, h.mode)
63
- assert_equal(10, h.size)
64
- assert_equal("", h.prefix)
65
- assert_equal("ustar", h.magic)
58
+ h = Minitar::PosixHeader.from_stream(header)
59
+ assert_equal "a" * 100, h.name
60
+ assert_equal 0o12345, h.mode
61
+ assert_equal 10, h.size
62
+ assert_equal "", h.prefix
63
+ assert_equal "ustar", h.magic
66
64
  end
67
65
 
68
66
  def test_from_stream_with_evil_name
69
67
  header = tar_file_header("a \0" + "\0" * 97, "", 0o12345, 10)
70
68
  header = StringIO.new(header)
71
- h = Archive::Tar::Minitar::PosixHeader.from_stream header
72
- assert_equal("a ", h.name)
69
+ h = Minitar::PosixHeader.from_stream header
70
+ assert_equal "a ", h.name
73
71
  end
74
72
 
75
73
  def test_valid_with_valid_header
76
74
  header = tar_file_header("a" * 100, "", 0o12345, 10)
77
75
  header = StringIO.new(header)
78
- h = Archive::Tar::Minitar::PosixHeader.from_stream header
76
+ h = Minitar::PosixHeader.from_stream header
79
77
 
80
78
  assert(h.valid?)
81
79
  end
@@ -85,7 +83,7 @@ class TestTarHeader < Minitest::Test
85
83
  io = StringIO.new(header)
86
84
 
87
85
  assert_raises(ArgumentError) do
88
- Archive::Tar::Minitar::PosixHeader.from_stream(io)
86
+ Minitar::PosixHeader.from_stream(io)
89
87
  end
90
88
  end
91
89
 
@@ -98,14 +96,14 @@ class TestTarHeader < Minitest::Test
98
96
 
99
97
  header = update_checksum(header)
100
98
  io = StringIO.new(header)
101
- header = Archive::Tar::Minitar::PosixHeader.from_stream(io)
99
+ header = Minitar::PosixHeader.from_stream(io)
102
100
 
103
- assert_equal(651, header.size)
101
+ assert_equal 651, header.size
104
102
  end
105
103
 
106
104
  def test_valid_with_invalid_header
107
105
  header = StringIO.new("testing")
108
- h = Archive::Tar::Minitar::PosixHeader.from_stream header
106
+ h = Minitar::PosixHeader.from_stream header
109
107
 
110
108
  refute(h.valid?)
111
109
  end