Compare commits

...

38 Commits
master ... 2.4

Author SHA1 Message Date
Robert Haines 6c4b7a9f90 Move to version `2.4.1` due to clash with `2.4`. 2025-01-05 18:15:02 +00:00
Geremia Taglialatela 3b4c2bfa22 Opt-in for MFA requirement explicitly on 2.4
As a pupular gem, `rubyzip` implicitly requires that all privileged
operations by any of the owners require OTP.

By explicitly setting `rubygems_mfa_required` metadata, the
gem will show "NEW VERSIONS REQUIRE MFA" and "VERSION PUBLISHED WITH
MFA" in the sidebar at https://rubygems.org/gems/rubyzip

NOTE: The explicit opt-in was introduced in the `master` branch via
1c06454, but has not been backported to `2.4`

Ref:
- https://blog.rubygems.org/2022/08/15/requiring-mfa-on-popular-gems.html
- https://guides.rubygems.org/mfa-requirement-opt-in/
2025-01-05 18:00:28 +00:00
Robert Haines e3eb62491b Make sure version number is 2.4.0.
And add a test to keep version numbers consistent from now on.

Fixes: #623
2025-01-05 11:43:53 +00:00
Robert Haines c09352b546 Bump version and Changelog for release. 2025-01-04 10:12:55 +00:00
Robert Haines 71bb069049 Update actions with latest rubies.
Also, allow failure on 'head' versions.
2025-01-04 09:54:58 +00:00
Robert Haines bb06f99b14 Update actions dependencies. 2024-10-26 13:36:30 +01:00
Robert Haines 3d95a8204f Update earliest Ruby version for MacOS builds in CI. 2024-10-26 13:35:43 +01:00
Tsutomu Katsube 56954b0b59 Suppress "literal string will be frozen in the future" warning
Ref: https://bugs.ruby-lang.org/issues/20205

This patch will suppress the "literal string will be frozen in the
future" warning on the 2.4 branch.

Steps to reproduce
---

Run the following commands with ruby 3.4.0preview1:

```console
$ cd /tmp
$ git clone git@github.com:rubyzip/rubyzip.git
$ cd rubyzip
$ git switch 2.4
$ bundle install
$ ruby -I lib -W:deprecated -e '
require "zip"

Zip::File.open("test/data/ntfs.zip") do |zip_file|
  zip_file.each do |entry|
    puts entry.get_input_stream.read
  end
end
'
```

Expected result
---

```console
ntfs test
```

Actual result
---

```console
/private/tmp/rubyzip/lib/zip/extra_field/ntfs.rb:54: warning: literal string will be frozen in the future
ntfs test
```

Environment
---

```console
$ ruby -v
ruby 3.4.0preview1 (2024-05-16 master 9d69619623) [x86_64-darwin23]
```
2024-09-21 09:06:36 +09:00
Robert Haines 6ff40f7a78 Fix setting and restoring `RUBYZIP_V3_API_WARN` in tests.
Make sure that it is reset to its original value so that we can set it
up front for all tests.
2024-04-09 18:05:05 +01:00
Robert Haines e05dc9b978 Improve version 3 API messages.
The messages now tell you where you have called the changed method from.
2024-04-09 17:53:27 +01:00
Jean Boussier a4c3f5bddb Fix deprecation in Entry#get_input_stream 2024-04-09 16:37:04 +01:00
Jean Boussier 57cff3338f Fix `File#write_buffer` to always return the given `io`
Ref: ef89a62b70

This fixes a regression in 2.4.rc1.
2024-04-09 10:05:18 +01:00
Robert Haines 0001864cfe Bump version, Changelog and README for release. 2024-04-08 16:15:44 +01:00
Jean Boussier 385ebd054a Ensure compatibility with `--enable-frozen-string-literal`
Ref: https://bugs.ruby-lang.org/issues/20205

In Ruby 3.4 string literals will be "chilled" by default. Meaning
they are still mutable, but will pretend to be frozen.

In most case it has no impact, just emit a few warnings there and
there, but there is one thing it impacts is the `StringIO.new('')`
pattern. `StringIO` checks if the given string is frozen, and if
it is will act as a read only IO.

This breaks rubyzip 2.x.

This commit make the 2.x branch compatible with frozen string literals.
2024-04-08 15:10:07 +01:00
Robert Haines 46689d7350 Add `DOSTime` to the post_install message. 2024-04-08 14:29:10 +01:00
Robert Haines ef89a62b70 Ensure `File.open_buffer` doesn't rewrite unchanged data.
This is a backport of 14b63f68 from trunk.
2024-04-08 12:44:12 +01:00
Robert Haines 900db76760 Handle the `extract` methods in `Entry` and `File`.
Add v3 versions and warning messages to the v2 versions. We need to do
these methods like this because the new versions are very different.
2024-03-10 17:21:53 +00:00
Robert Haines 14efdd1cc4 Add `DOSTime#<=>` and a warning message to `DOSTime#dos_equals`.
`#dos_equals` now uses `#==` for its implementation.
2024-03-10 11:34:36 +00:00
Robert Haines 02faddaf44 Add warning messages to `File#get_output_stream`. 2024-03-10 09:00:17 +00:00
Robert Haines 9aa5964262 Add warning messages to the `File` class methods.
* `new`
 * `open`
 * `open_buffer`
2024-03-10 08:03:49 +00:00
Robert Haines 13f4ea766f Update gemspec. 2024-03-03 21:10:08 +00:00
Robert Haines 3910870f3a Remove Coveralls/Simplecov from this branch.
We don't use it in CI anyway.
2024-03-03 20:56:50 +00:00
Robert Haines 07d833ca78 Add warning messages to `InputStream.open`. 2024-03-03 18:06:51 +00:00
Robert Haines 6bbda380fe Add warning messages to deprectated methods.
* File.add_buffer
 * InputStream.open_buffer
2024-03-02 18:50:47 +00:00
Robert Haines a6e6c3c469 Update rubocop fails. 2024-03-02 18:38:00 +00:00
Robert Haines b691a4b72c Minor updates to the Actions workflow. 2024-03-02 08:59:52 +00:00
Robert Haines f68877920a Update File.split API to allow v3.0 calling style. 2024-03-02 08:23:27 +00:00
Robert Haines 13781b20d3 Add a warning when run on Ruby < 3.0. 2024-03-01 23:04:02 +00:00
Robert Haines 4b1cfba9db Add warning message (and tests) to OutputStream. 2024-03-01 18:05:06 +00:00
Robert Haines 5e9ee53c70 Add warning message to InputStream. 2024-03-01 18:05:06 +00:00
Robert Haines cb0505d735 Add a switchable warning message re the v3 API.
Switched via an environment variable, and tested.
2024-03-01 18:05:06 +00:00
Robert Haines 49950d924c Update Entry#new API to allow v3.0 calling style.
See https://github.com/rubyzip/rubyzip/wiki/Updating-to-version-3.x#new-1
for details.
2024-03-01 18:05:06 +00:00
Robert Haines a17da19e0c Update InputStream API to allow v3.0 calling style.
See https://github.com/rubyzip/rubyzip/wiki/Updating-to-version-3.x#zipinputstream
for details.
2024-03-01 18:05:06 +00:00
Robert Haines 7c1a8fbf8f Update OutputStream API to allow v3.0 calling style.
See https://github.com/rubyzip/rubyzip/wiki/Updating-to-version-3.x#zipoutputstream
for details.
2024-03-01 18:05:06 +00:00
Robert Haines 77611045f1 Switch to GitHub Actions on the `2.3.2` branch. 2022-02-06 14:31:04 +00:00
Robert Haines 2f1c1ea400 Move to using a post install message for 3.0 warning. 2021-07-05 20:13:36 +01:00
Robert Haines 16de339666 Print banner text re v3.0.0 when `zip` is required. 2021-07-03 12:12:22 +01:00
Robert Haines 84d7a66abc Bump version number and Changelog. 2021-07-03 12:10:30 +01:00
30 changed files with 711 additions and 144 deletions

81
.github/workflows/tests.yml vendored Normal file
View File

@ -0,0 +1,81 @@
name: Tests
on: [push, pull_request]
jobs:
test:
strategy:
fail-fast: false
matrix:
os: [ubuntu]
ruby: ['2.4', '2.5', '2.6', '2.7', '3.0', '3.1', '3.2', '3.3', '3.4', head, jruby, truffleruby]
include:
- os: macos
ruby: '2.6'
runs-on: ${{ matrix.os }}-latest
continue-on-error: ${{ endsWith(matrix.ruby, 'head') }}
steps:
- name: Checkout rubyzip code
uses: actions/checkout@v4
- name: Install and set up ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby }}
rubygems: '3.2.3'
bundler-cache: true
- name: Run the tests
env:
RUBYOPT: -v
JRUBY_OPTS: --debug
FULL_ZIP64_TEST: 1
run: bundle exec rake
test-frozen-string-literal:
strategy:
fail-fast: false
matrix:
os: [ubuntu]
ruby: ['3.3', '3.4', head]
runs-on: ${{ matrix.os }}-latest
continue-on-error: true
steps:
- name: Checkout rubyzip code
uses: actions/checkout@v4
- name: Install and set up ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby }}
bundler-cache: true
- name: Run the tests
env:
RUBYOPT: --enable-frozen-string-literal
FULL_ZIP64_TEST: 1
run: bundle exec rake
test-yjit:
strategy:
fail-fast: false
matrix:
os: [ubuntu, macos]
ruby: ['3.1', '3.2', '3.3', '3.4', head]
runs-on: ${{ matrix.os }}-latest
continue-on-error: true
steps:
- name: Checkout rubyzip code
uses: actions/checkout@v4
- name: Install and set up ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby }}
bundler-cache: true
- name: Run the tests
env:
RUBYOPT: --enable-yjit -v
FULL_ZIP64_TEST: 1
run: bundle exec rake

View File

@ -23,11 +23,6 @@ Lint/SuppressedException:
Exclude:
- 'test/**/*.rb'
# Allow this "useless" test, as we are testing <=> here.
Lint/UselessComparison:
Exclude:
- 'test/entry_test.rb'
# Turn off ABC metrics for the tests and set a workable max given
# the current state of the code.
Metrics/AbcSize:

View File

@ -9,7 +9,7 @@
# Offense count: 15
# Configuration parameters: CountComments.
Metrics/ClassLength:
Max: 580
Max: 600
# Offense count: 26
Metrics/CyclomaticComplexity:
@ -18,7 +18,7 @@ Metrics/CyclomaticComplexity:
# Offense count: 120
# Configuration parameters: CountComments, ExcludedMethods.
Metrics/MethodLength:
Max: 30
Max: 32
# Offense count: 2
# Configuration parameters: CountKeywordArgs.

View File

@ -1,9 +0,0 @@
require 'coveralls'
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new([
SimpleCov::Formatter::HTMLFormatter,
Coveralls::SimpleCov::Formatter
])
SimpleCov.start do
add_filter '/test'
end

View File

@ -1,34 +0,0 @@
language: ruby
dist: xenial
cache: bundler
rvm:
- 2.4
- 2.5
- 2.6
- 2.7
- ruby-head
matrix:
fast_finish: true
include:
- rvm: jruby-9.2
jdk: openjdk8
- rvm: jruby-9.2
jdk: openjdk11
- rvm: jruby-head
jdk: openjdk11
- rvm: rbx-4
allow_failures:
- rvm: ruby-head
- rvm: rbx-4
- rvm: jruby-head
before_install:
- gem --version
before_script:
- echo `whereis zip`
- echo `whereis unzip`
env:
global:
- JRUBY_OPTS="--debug"
- COVERALLS_PARALLEL=true
notifications:
webhooks: https://coveralls.io/webhook

View File

@ -1,5 +1,36 @@
# X.X.X (Next)
# 2.4.1 (2025-01-05)
*This is a re-release of version 2.4 with a full version number string. We need to move to version 2.4.1 due to the canonical version number 2.4 now being taken in Rubygems.*
Tooling:
- Opt-in for MFA requirement explicitly on 2.4 branch.
# 2.4 (2025-01-04) - Yanked
*Yanked due to incorrect version number format (2.4 vs 2.4.0).*
- Ensure compatibility with `--enable-frozen-string-literal`.
- Ensure `File.open_buffer` doesn't rewrite unchanged data. This is a backport of the fix on the 3.x branch.
- Enable use of the version 3 calling style (mainly named parameters) wherever possible, while retaining version 2.x compatibility.
- Add (switchable) warning messages to methods that are changed or removed in version 3.x.
Tooling:
- Switch to using GitHub Actions (from Travis).
- Update Rubocop versions and configuration.
- Update actions with latest rubies.
# 2.3.2 (2021-07-05)
- This is a dummy release to warn about breaking changes coming in version 3.0. This updated version uses the Gem `post_install_message` instead of printing to `STDERR`.
# 2.3.1 (2021-07-03)
- This is a dummy release to warn about breaking changes coming in version 3.0.
# 2.3.0 (2020-03-14)
- Fix frozen string literal error [#431](https://github.com/rubyzip/rubyzip/pull/431)

View File

@ -1,7 +1,7 @@
# rubyzip
[![Gem Version](https://badge.fury.io/rb/rubyzip.svg)](http://badge.fury.io/rb/rubyzip)
[![Build Status](https://secure.travis-ci.org/rubyzip/rubyzip.svg)](http://travis-ci.org/rubyzip/rubyzip)
[![Tests](https://github.com/rubyzip/rubyzip/actions/workflows/tests.yml/badge.svg)](https://github.com/rubyzip/rubyzip/actions/workflows/tests.yml)
[![Code Climate](https://codeclimate.com/github/rubyzip/rubyzip.svg)](https://codeclimate.com/github/rubyzip/rubyzip)
[![Coverage Status](https://img.shields.io/coveralls/rubyzip/rubyzip.svg)](https://coveralls.io/r/rubyzip/rubyzip?branch=master)
@ -9,18 +9,26 @@ Rubyzip is a ruby library for reading and writing zip files.
## Important note
The Rubyzip interface has changed!!! No need to do `require "zip/zip"` and `Zip` prefix in class names removed.
Rubyzip 2.4 is intended to be the last release in the 2.x series. Please get ready for version 3.0.
If you have issues with any third-party gems that require an old version of rubyzip, you can use this workaround:
### Updating to version 3.0
```ruby
gem 'rubyzip', '>= 1.0.0' # will load new rubyzip version
gem 'zip-zip' # will load compatibility for old rubyzip API.
```
The public API of some classes has been modernized to use named parameters for optional arguments. Also some methods have been changed or removed. Please check your usage of the following Rubyzip classes:
* `File`
* `Entry`
* `InputStream`
* `OutputStream`
* `DOSTime`
**Please see [Updating to version 3.x](https://github.com/rubyzip/rubyzip/wiki/Updating-to-version-3.x) in the wiki for details.**
## Requirements
- Ruby 2.4 or greater (for rubyzip 2.0; use 1.x for older rubies)
Version 3.x requires at least Ruby 3.0.
Version 2.x requires at least Ruby 2.4, and is known to work on Ruby 3.x.
It is not recommended to use any versions of Rubyzip earlier than 2.3 due to security issues.
## Installation
@ -188,7 +196,7 @@ If `::Zip::InputStream` finds such entry in the zip archive it will raise an exc
Rubyzip supports reading/writing zip files with traditional zip encryption (a.k.a. "ZipCrypto"). AES encryption is not yet supported. It can be used with buffer streams, e.g.:
```ruby
Zip::OutputStream.write_buffer(::StringIO.new(''), Zip::TraditionalEncrypter.new('password')) do |out|
Zip::OutputStream.write_buffer(::StringIO.new, Zip::TraditionalEncrypter.new('password')) do |out|
out.put_next_entry("my_file.txt")
out.write my_data
end.string

View File

@ -34,6 +34,25 @@ require 'zip/streamable_directory'
require 'zip/errors'
module Zip
V3_API_WARNING_MSG = <<~END_MSG
You have called '%s' (from %s).
This method is changing or deprecated in version 3.0.0. Please see
https://github.com/rubyzip/rubyzip/wiki/Updating-to-version-3.x
for more information.
END_MSG
def self.warn_about_v3_api(method)
return unless ENV['RUBYZIP_V3_API_WARN']
loc = caller_locations(2, 1)[0]
from = "#{loc.path.split('/').last}:#{loc.lineno}"
warn format(V3_API_WARNING_MSG, method, from)
end
if ENV['RUBYZIP_V3_API_WARN'] && RUBY_VERSION < '3.0'
warn 'RubyZip 3.0 will require Ruby 3.0 or later.'
end
extend self
attr_accessor :unicode_names,
:on_exists_proc,

View File

@ -24,9 +24,17 @@ module Zip
((year - 1980) << 9)
end
# Dos time is only stored with two seconds accuracy
def dos_equals(other)
to_i / 2 == other.to_i / 2
Zip.warn_about_v3_api('DOSTime#dos_equals')
self == other
end
# Dos time is only stored with two seconds accuracy.
def <=>(other)
return unless other.kind_of?(Time)
(to_i / 2) <=> (other.to_i / 2)
end
# Create a DOSTime instance from a vanilla Time instance.
@ -41,9 +49,8 @@ module Zip
day = (0b11111 & bin_dos_date)
month = (0b111100000 & bin_dos_date) >> 5
year = ((0b1111111000000000 & bin_dos_date) >> 9) + 1980
begin
local(year, month, day, hour, minute, second)
end
local(year, month, day, hour, minute, second)
end
end
end

View File

@ -52,26 +52,41 @@ module Zip
raise ::Zip::EntryNameError, "Illegal ZipEntry name '#{name}', name must not start with /"
end
def initialize(*args)
name = args[1] || ''
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
def initialize(zipfile = nil, name = nil, *args)
name ||= ''
check_name(name)
set_default_vars_values
@fstype = ::Zip::RUNNING_ON_WINDOWS ? ::Zip::FSTYPE_FAT : ::Zip::FSTYPE_UNIX
@zipfile = args[0] || ''
@zipfile = zipfile || ''
@name = name
@comment = args[2] || ''
@extra = args[3] || ''
@compressed_size = args[4] || 0
@crc = args[5] || 0
@compression_method = args[6] || ::Zip::Entry::DEFLATED
@size = args[7] || 0
@time = args[8] || ::Zip::DOSTime.now
if (args_hash = args.first).kind_of?(::Hash)
@comment = args_hash[:comment] || ''
@extra = args_hash[:extra] || ''
@compressed_size = args_hash[:compressed_size] || 0
@crc = args_hash[:crc] || 0
@compression_method = args_hash[:compression_method] || ::Zip::Entry::DEFLATED
@size = args_hash[:size] || 0
@time = args_hash[:time] || ::Zip::DOSTime.now
else
Zip.warn_about_v3_api('Zip::Entry.new') unless args.empty?
@comment = args[0] || ''
@extra = args[1] || ''
@compressed_size = args[2] || 0
@crc = args[3] || 0
@compression_method = args[4] || ::Zip::Entry::DEFLATED
@size = args[5] || 0
@time = args[6] || ::Zip::DOSTime.now
end
@ftype = name_is_directory? ? :directory : :file
@extra = ::Zip::ExtraField.new(@extra.to_s) unless @extra.kind_of?(::Zip::ExtraField)
end
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
def encrypted?
gp_flags & 1 == 1
@ -174,6 +189,8 @@ module Zip
# NB: The caller is responsible for making sure dest_path is safe, if it
# is passed.
def extract(dest_path = nil, &block)
Zip.warn_about_v3_api('Zip::Entry#extract')
if dest_path.nil? && !name_safe?
warn "WARNING: skipped '#{@name}' as unsafe."
return self
@ -188,6 +205,28 @@ module Zip
self
end
# Extracts this entry to a file at `entry_path`, with
# `destination_directory` as the base location in the filesystem.
#
# NB: The caller is responsible for making sure `destination_directory` is
# safe, if it is passed.
def extract_v3(entry_path = @name, destination_directory: '.', &block)
dest_dir = ::File.absolute_path(destination_directory || '.')
extract_path = ::File.absolute_path(::File.join(dest_dir, entry_path))
unless extract_path.start_with?(dest_dir)
warn "WARNING: skipped extracting '#{@name}' to '#{extract_path}' as unsafe."
return self
end
block ||= proc { ::Zip.on_exists_proc }
raise "unknown file type #{inspect}" unless directory? || file? || symlink?
__send__(:"create_#{ftype}", extract_path, &block)
self
end
def to_s
@name
end
@ -506,7 +545,7 @@ module Zip
keys_equal = %w[compression_method crc compressed_size size name extra filepath].all? do |k|
other.__send__(k.to_sym) == __send__(k.to_sym)
end
keys_equal && time.dos_equals(other.time)
keys_equal && time == other.time
end
def <=>(other)
@ -532,7 +571,7 @@ module Zip
raise "unknown @file_type #{@ftype}"
end
else
zis = ::Zip::InputStream.new(@zipfile, local_header_offset)
zis = ::Zip::InputStream.new(@zipfile, offset: local_header_offset)
zis.instance_variable_set(:@complete_entry, self)
zis.get_next_entry
if block_given?

View File

@ -51,7 +51,7 @@ module Zip
# reserved 0 and tag 1
s = [0, 1].pack('Vv')
tag1 = ''.force_encoding(Encoding::BINARY)
tag1 = ''.b
if @mtime
tag1 << [to_ntfs_time(@mtime)].pack('Q<')
if @atime

View File

@ -59,7 +59,7 @@ module Zip
def pack_for_c_dir
# central directory entries contain only fields that didn't fit in the main entry part
packed = ''.force_encoding('BINARY')
packed = ''.b
packed << [@original_size].pack('Q<') if @original_size
packed << [@compressed_size].pack('Q<') if @compressed_size
packed << [@relative_header_offset].pack('Q<') if @relative_header_offset

View File

@ -73,12 +73,17 @@ module Zip
# Opens a zip archive. Pass true as the second parameter to create
# a new archive if it doesn't exist already.
def initialize(path_or_io, create = false, buffer = false, options = {})
def initialize(path_or_io, dep_create = false, dep_buffer = false,
create: false, buffer: false, **options)
super()
Zip.warn_about_v3_api('File#new') if dep_create || dep_buffer
options = DEFAULT_OPTIONS.merge(options)
@name = path_or_io.respond_to?(:path) ? path_or_io.path : path_or_io
@comment = ''
@create = create ? true : false # allow any truthy value to mean true
@create = create || dep_create ? true : false # allow any truthy value to mean true
buffer ||= dep_buffer
if ::File.size?(@name.to_s)
# There is a file, which exists, that is associated with this zip.
@ -94,6 +99,7 @@ module Zip
end
elsif buffer && path_or_io.size > 0
# This zip is probably a non-empty StringIO.
@create = false
read_from_stream(path_or_io)
elsif @create
# This zip is completely new/empty and is to be created.
@ -117,8 +123,10 @@ module Zip
# Similar to ::new. If a block is passed the Zip::File object is passed
# to the block and is automatically closed afterwards, just as with
# ruby's builtin File::open method.
def open(file_name, create = false, options = {})
zf = ::Zip::File.new(file_name, create, false, options)
def open(file_name, dep_create = false, create: false, **options)
Zip.warn_about_v3_api('Zip::File.open') if dep_create
zf = ::Zip::File.new(file_name, create: (dep_create || create), buffer: false, **options)
return zf unless block_given?
begin
@ -130,7 +138,9 @@ module Zip
# Same as #open. But outputs data to a buffer instead of a file
def add_buffer
io = ::StringIO.new('')
Zip.warn_about_v3_api('Zip::File.add_buffer')
io = ::StringIO.new
zf = ::Zip::File.new(io, true, true)
yield zf
zf.write_buffer(io)
@ -140,7 +150,7 @@ module Zip
# stream, and outputs data to a buffer.
# (This can be used to extract data from a
# downloaded zip archive without first saving it to disk.)
def open_buffer(io, options = {})
def open_buffer(io, **options)
unless IO_METHODS.map { |method| io.respond_to?(method) }.all? || io.kind_of?(String)
raise "Zip::File.open_buffer expects a String or IO-like argument (responds to #{IO_METHODS.join(', ')}). Found: #{io.class}"
end
@ -150,7 +160,7 @@ module Zip
# https://github.com/rubyzip/rubyzip/issues/119
io.binmode if io.respond_to?(:binmode)
zf = ::Zip::File.new(io, true, true, options)
zf = ::Zip::File.new(io, create: true, buffer: true, **options)
return zf unless block_given?
yield zf
@ -228,18 +238,24 @@ module Zip
end
# Splits an archive into parts with segment size
def split(zip_file_name, segment_size = MAX_SEGMENT_SIZE, delete_zip_file = true, partial_zip_file_name = nil)
def split(zip_file_name,
dep_segment_size = MAX_SEGMENT_SIZE, dep_delete_zip_file = true, dep_partial_zip_file_name = nil,
segment_size: MAX_SEGMENT_SIZE, delete_zip_file: nil, partial_zip_file_name: nil)
raise Error, "File #{zip_file_name} not found" unless ::File.exist?(zip_file_name)
raise Errno::ENOENT, zip_file_name unless ::File.readable?(zip_file_name)
if dep_segment_size != MAX_SEGMENT_SIZE || !dep_delete_zip_file || dep_partial_zip_file_name
Zip.warn_about_v3_api('Zip::File.split')
end
zip_file_size = ::File.size(zip_file_name)
segment_size = get_segment_size_for_split(segment_size)
segment_size = get_segment_size_for_split(segment_size || dep_segment_size)
return if zip_file_size <= segment_size
segment_count = get_segment_count_for_split(zip_file_size, segment_size)
# Checking for correct zip structure
::Zip::File.open(zip_file_name) {}
partial_zip_file_name = get_partial_zip_file_name(zip_file_name, partial_zip_file_name)
partial_zip_file_name = get_partial_zip_file_name(zip_file_name, (partial_zip_file_name || dep_partial_zip_file_name))
szip_file_index = 0
::File.open(zip_file_name, 'rb') do |zip_file|
until zip_file.eof?
@ -247,6 +263,7 @@ module Zip
save_splited_part(zip_file, partial_zip_file_name, zip_file_size, szip_file_index, segment_size, segment_count)
end
end
delete_zip_file = delete_zip_file.nil? ? dep_delete_zip_file : delete_zip_file
::File.delete(zip_file_name) if delete_zip_file
szip_file_index
end
@ -264,26 +281,45 @@ module Zip
# specified. If a block is passed the stream object is passed to the block and
# the stream is automatically closed afterwards just as with ruby's builtin
# File.open method.
def get_output_stream(entry, permission_int = nil, comment = nil,
extra = nil, compressed_size = nil, crc = nil,
compression_method = nil, size = nil, time = nil,
# rubocop:disable Metrics/ParameterLists, Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
def get_output_stream(entry,
dep_permission_int = nil, dep_comment = nil,
dep_extra = nil, dep_compressed_size = nil, dep_crc = nil,
dep_compression_method = nil, dep_size = nil, dep_time = nil,
permission_int: nil, comment: nil,
extra: nil, compressed_size: nil, crc: nil,
compression_method: nil, size: nil, time: nil,
&a_proc)
unless dep_permission_int.nil? && dep_comment.nil? && dep_extra.nil? &&
dep_compressed_size.nil? && dep_crc.nil? && dep_compression_method.nil? &&
dep_size.nil? && dep_time.nil?
Zip.warn_about_v3_api('Zip::File#get_output_stream')
end
new_entry =
if entry.kind_of?(Entry)
entry
else
Entry.new(@name, entry.to_s, comment, extra, compressed_size, crc, compression_method, size, time)
Entry.new(@name, entry.to_s,
comment: (comment || dep_comment),
extra: (extra || dep_extra),
compressed_size: (compressed_size || dep_compressed_size),
crc: (crc || dep_crc),
compression_method: (compression_method || dep_compression_method),
size: (size || dep_size),
time: (time || dep_time))
end
if new_entry.directory?
raise ArgumentError,
"cannot open stream to directory entry - '#{new_entry}'"
end
new_entry.unix_perms = permission_int
new_entry.unix_perms = (permission_int || dep_permission_int)
zip_streamable_entry = StreamableStream.new(new_entry)
@entry_set << zip_streamable_entry
zip_streamable_entry.get_output_stream(&a_proc)
end
# rubocop:enable Metrics/ParameterLists, Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
# Returns the name of the zip archive
def to_s
@ -336,11 +372,25 @@ module Zip
# Extracts entry to file dest_path.
def extract(entry, dest_path, &block)
Zip.warn_about_v3_api('Zip::File#extract')
block ||= proc { ::Zip.on_exists_proc }
found_entry = get_entry(entry)
found_entry.extract(dest_path, &block)
end
# Extracts `entry` to a file at `entry_path`, with `destination_directory`
# as the base location in the filesystem.
#
# NB: The caller is responsible for making sure `destination_directory` is
# safe, if it is passed.
def extract_v3(entry, entry_path = nil, destination_directory: '.', &block)
block ||= proc { ::Zip.on_exists_proc }
found_entry = get_entry(entry)
entry_path ||= found_entry.name
found_entry.extract_v3(entry_path, destination_directory: destination_directory, &block)
end
# Commits changes that has been made since the previous commit to
# the zip archive.
def commit
@ -361,7 +411,9 @@ module Zip
end
# Write buffer write changes to buffer and return
def write_buffer(io = ::StringIO.new(''))
def write_buffer(io = ::StringIO.new)
return io unless commit_required?
::Zip::OutputStream.write_buffer(io) do |zos|
@entry_set.each { |e| e.write_to_zip_output_stream(zos) }
zos.comment = comment

View File

@ -239,7 +239,7 @@ module Zip
end
def open(filename, mode = 'r', permissions = 0o644, &block)
mode.delete!('b') # ignore b option
mode = mode.delete('b') # ignore b option
case mode
when 'r'
@mapped_zip.get_input_stream(filename, &block)
@ -619,7 +619,7 @@ module Zip
end
def expand_path(path)
expanded = path.start_with?('/') ? path : ::File.join(@pwd, path)
expanded = path.start_with?('/') ? path.dup : ::File.join(@pwd, path)
expanded.gsub!(/\/\.(\/|$)/, '')
expanded.gsub!(/[^\/]+\/\.\.(\/|$)/, '')
expanded.empty? ? '/' : expanded

View File

@ -3,11 +3,11 @@ module Zip
def initialize(*args)
super
@buffer = +''
@buffer = ''.b
@zlib_inflater = ::Zlib::Inflate.new(-Zlib::MAX_WBITS)
end
def read(length = nil, outbuf = '')
def read(length = nil, outbuf = ''.b)
return (length.nil? || length.zero? ? '' : nil) if eof
while length.nil? || (@buffer.bytesize < length)

View File

@ -49,11 +49,17 @@ module Zip
#
# @param context [String||IO||StringIO] file path or IO/StringIO object
# @param offset [Integer] offset in the IO/StringIO
def initialize(context, offset = 0, decrypter = nil)
def initialize(context, dep_offset = 0, dep_decrypter = nil, offset: 0, decrypter: nil)
super()
if !dep_offset.zero? || !dep_decrypter.nil?
Zip.warn_about_v3_api('Zip::InputStream.new')
end
offset = dep_offset if offset.zero?
@archive_io = get_io(context, offset)
@decompressor = ::Zip::NullDecompressor
@decrypter = decrypter || ::Zip::NullDecrypter.new
@decrypter = decrypter || dep_decrypter || ::Zip::NullDecrypter.new
@current_entry = nil
end
@ -89,8 +95,14 @@ module Zip
# Same as #initialize but if a block is passed the opened
# stream is passed to the block and closed when the block
# returns.
def open(filename_or_io, offset = 0, decrypter = nil)
zio = new(filename_or_io, offset, decrypter)
def open(filename_or_io, dep_offset = 0, dep_decrypter = nil, offset: 0, decrypter: nil)
if !dep_offset.zero? || !dep_decrypter.nil?
Zip.warn_about_v3_api('Zip::InputStream.new')
end
offset = dep_offset if offset.zero?
zio = new(filename_or_io, offset: offset, decrypter: decrypter || dep_decrypter)
return zio unless block_given?
begin
@ -101,7 +113,8 @@ module Zip
end
def open_buffer(filename_or_io, offset = 0)
warn 'open_buffer is deprecated!!! Use open instead!'
Zip.warn_about_v3_api('Zip::InputStream.open_buffer')
::Zip::InputStream.open(filename_or_io, offset)
end
end

View File

@ -6,14 +6,14 @@ module Zip
class << self
def copy_stream(ostream, istream)
ostream.write(istream.read(CHUNK_SIZE, '')) until istream.eof?
ostream.write(istream.read(CHUNK_SIZE, ''.b)) until istream.eof?
end
def copy_stream_n(ostream, istream, nbytes)
toread = nbytes
while toread > 0 && !istream.eof?
tr = toread > CHUNK_SIZE ? CHUNK_SIZE : toread
ostream.write(istream.read(tr, ''))
ostream.write(istream.read(tr, ''.b))
toread -= tr
end
end

View File

@ -11,13 +11,13 @@ module Zip
super
@lineno = 0
@pos = 0
@output_buffer = ''
@output_buffer = ''.b
end
attr_accessor :lineno
attr_reader :pos
def read(number_of_bytes = nil, buf = '')
def read(number_of_bytes = nil, buf = ''.b)
tbuf = if @output_buffer.bytesize > 0
if number_of_bytes <= @output_buffer.bytesize
@output_buffer.slice!(0, number_of_bytes)
@ -26,7 +26,7 @@ module Zip
rbuf = sysread(number_of_bytes, buf)
out = @output_buffer
out << rbuf if rbuf
@output_buffer = ''
@output_buffer = ''.b
out
end
else
@ -93,7 +93,7 @@ module Zip
def flush
ret_val = @output_buffer
@output_buffer = ''
@output_buffer = ''.b
ret_val
end

View File

@ -24,10 +24,13 @@ module Zip
# Opens the indicated zip file. If a file with that name already
# exists it will be overwritten.
def initialize(file_name, stream = false, encrypter = nil)
def initialize(file_name, dep_stream = false, dep_encrypter = nil, stream: false, encrypter: nil)
super()
Zip.warn_about_v3_api('Zip::OutputStream.new') if dep_stream || !dep_encrypter.nil?
@file_name = file_name
@output_stream = if stream
@output_stream = if stream || dep_stream
iostream = @file_name.dup
iostream.reopen(@file_name)
iostream.rewind
@ -37,7 +40,7 @@ module Zip
end
@entry_set = ::Zip::EntrySet.new
@compressor = ::Zip::NullCompressor.instance
@encrypter = encrypter || ::Zip::NullEncrypter.new
@encrypter = encrypter || dep_encrypter || ::Zip::NullEncrypter.new
@closed = false
@current_entry = nil
@comment = nil
@ -47,19 +50,23 @@ module Zip
# stream is passed to the block and closed when the block
# returns.
class << self
def open(file_name, encrypter = nil)
def open(file_name, dep_encrypter = nil, encrypter: nil)
return new(file_name) unless block_given?
zos = new(file_name, false, encrypter)
Zip.warn_about_v3_api('Zip::OutputStream.open') unless dep_encrypter.nil?
zos = new(file_name, stream: false, encrypter: (encrypter || dep_encrypter))
yield zos
ensure
zos.close if zos
end
# Same as #open but writes to a filestream instead
def write_buffer(io = ::StringIO.new(''), encrypter = nil)
def write_buffer(io = ::StringIO.new, dep_encrypter = nil, encrypter: nil)
Zip.warn_about_v3_api('Zip::OutputStream.write_buffer') unless dep_encrypter.nil?
io.binmode if io.respond_to?(:binmode)
zos = new(io, true, encrypter)
zos = new(io, stream: true, encrypter: (encrypter || dep_encrypter))
yield zos
zos.close_buffer
end

View File

@ -5,7 +5,7 @@ module Zip
@read_so_far = 0
end
def read(length = nil, outbuf = '')
def read(length = nil, outbuf = ''.b)
return (length.nil? || length.zero? ? '' : nil) if eof
if length.nil? || (@read_so_far + length) > decompressed_size

View File

@ -1,3 +1,3 @@
module Zip
VERSION = '2.3.0'
VERSION = '2.4.1'
end

View File

@ -5,8 +5,10 @@ require 'zip/version'
Gem::Specification.new do |s|
s.name = 'rubyzip'
s.version = ::Zip::VERSION
s.authors = ['Alexander Simonov']
s.email = ['alex@simonov.me']
s.authors = ['Robert Haines', 'John Lees-Miller', 'Alexander Simonov']
s.email = [
'hainesr@gmail.com', 'jdleesmiller@gmail.com', 'alex@simonov.me'
]
s.homepage = 'http://github.com/rubyzip/rubyzip'
s.platform = Gem::Platform::RUBY
s.summary = 'rubyzip is a ruby module for reading and writing zip files'
@ -14,16 +16,42 @@ Gem::Specification.new do |s|
s.require_paths = ['lib']
s.license = 'BSD 2-Clause'
s.metadata = {
'bug_tracker_uri' => 'https://github.com/rubyzip/rubyzip/issues',
'changelog_uri' => "https://github.com/rubyzip/rubyzip/blob/v#{s.version}/Changelog.md",
'documentation_uri' => "https://www.rubydoc.info/gems/rubyzip/#{s.version}",
'source_code_uri' => "https://github.com/rubyzip/rubyzip/tree/v#{s.version}",
'wiki_uri' => 'https://github.com/rubyzip/rubyzip/wiki'
'bug_tracker_uri' => 'https://github.com/rubyzip/rubyzip/issues',
'changelog_uri' => "https://github.com/rubyzip/rubyzip/blob/v#{s.version}/Changelog.md",
'documentation_uri' => "https://www.rubydoc.info/gems/rubyzip/#{s.version}",
'source_code_uri' => "https://github.com/rubyzip/rubyzip/tree/v#{s.version}",
'wiki_uri' => 'https://github.com/rubyzip/rubyzip/wiki',
'rubygems_mfa_required' => 'true'
}
s.required_ruby_version = '>= 2.4'
s.add_development_dependency 'coveralls', '~> 0.7'
s.add_development_dependency 'minitest', '~> 5.4'
s.add_development_dependency 'pry', '~> 0.10'
s.add_development_dependency 'rake', '~> 12.3', '>= 12.3.3'
s.add_development_dependency 'rubocop', '~> 0.79'
s.post_install_message = <<~ENDBANNER
RubyZip 3.0 is coming!
**********************
The public API of some Rubyzip classes has been modernized to use named
parameters for optional arguments. Please check your usage of the
following classes:
* `Zip::File`
* `Zip::Entry`
* `Zip::InputStream`
* `Zip::OutputStream`
* `Zip::DOSTime`
Run your test suite with the `RUBYZIP_V3_API_WARN` environment
variable set to see warnings about usage of the old API. This will
help you to identify any changes that you need to make to your code.
See https://github.com/rubyzip/rubyzip/wiki/Updating-to-version-3.x for
more information.
Please ensure that your Gemfiles and .gemspecs are suitably restrictive
to avoid an unexpected breakage when 3.0 is released (e.g. ~> 2.3.0).
See https://github.com/rubyzip/rubyzip for details. The Changelog also
lists other enhancements and bugfixes that have been implemented since
version 2.3.0.
ENDBANNER
end

View File

@ -1,6 +1,12 @@
require 'test_helper'
class ConstantsTest < MiniTest::Test
def test_version_number_format
# Should at least start with MAJoR.MINOR.PATCH, but
# allow for additional version information after that.
assert_match(/\A\d+\.\d+\.\d+/, Zip::VERSION)
end
def test_compression_methods
assert_equal(0, Zip::COMPRESSION_METHOD_STORE)
assert_equal(1, Zip::COMPRESSION_METHOD_SHRINK)

View File

@ -19,7 +19,7 @@ class EncryptionTest < MiniTest::Test
@rand = [250, 143, 107, 13, 143, 22, 155, 75, 228, 150, 12]
@output = ::Zip::DOSTime.stub(:now, ::Zip::DOSTime.new(2014, 12, 17, 15, 56, 24)) do
Random.stub(:rand, ->(_range) { @rand.shift }) do
Zip::OutputStream.write_buffer(::StringIO.new(''), Zip::TraditionalEncrypter.new('password')) do |zos|
Zip::OutputStream.write_buffer(::StringIO.new, Zip::TraditionalEncrypter.new('password')) do |zos|
zos.put_next_entry('file1.txt')
zos.write ::File.open(INPUT_FILE1).read
end.string

View File

@ -104,17 +104,27 @@ class ZipFileTest < MiniTest::Test
end
def test_open_buffer_with_string
string = File.read('test/data/rubycode.zip')
data = File.read('test/data/rubycode.zip', mode: 'rb')
string = data.dup
::Zip::File.open_buffer string do |zf|
assert zf.entries.map(&:name).include?('zippedruby1.rb')
end
# Ensure the buffer hasn't changed.
assert_equal(data, string)
end
def test_open_buffer_with_stringio
string_io = StringIO.new File.read('test/data/rubycode.zip')
data = File.read('test/data/rubycode.zip', mode: 'rb')
string_io = StringIO.new(data.dup)
::Zip::File.open_buffer string_io do |zf|
assert zf.entries.map(&:name).include?('zippedruby1.rb')
end
# Ensure the buffer hasn't changed.
assert_equal(data, string_io.string)
end
def test_close_buffer_with_stringio
@ -123,6 +133,18 @@ class ZipFileTest < MiniTest::Test
assert_nil zf.close
end
def test_open_buffer_without_block_write_buffer_does_nothing
data = File.read('test/data/rubycode.zip', mode: 'rb')
string_io = StringIO.new(data.dup)
zf = ::Zip::File.open_buffer(string_io)
assert zf.entries.map(&:name).include?('zippedruby1.rb')
# Ensure the buffer isn't changed.
assert_same string_io, zf.write_buffer(string_io)
assert_equal(data, string_io.string)
end
def test_open_buffer_no_op_does_not_change_file
Dir.mktmpdir do |tmp|
test_zip = File.join(tmp, 'test.zip')
@ -481,7 +503,7 @@ class ZipFileTest < MiniTest::Test
zf = ::Zip::File.new(TEST_ZIP.zip_name)
old_name = zf.entries.first
zf.rename(old_name, new_name)
io = ::StringIO.new('')
io = ::StringIO.new
buffer = zf.write_buffer(io)
File.open(TEST_ZIP.zip_name, 'wb') { |f| f.write buffer.string }
zf_read = ::Zip::File.new(TEST_ZIP.zip_name)
@ -630,7 +652,7 @@ class ZipFileTest < MiniTest::Test
end
def test_streaming
fname = ::File.join(::File.expand_path(::File.dirname(__FILE__)), '../README.md')
fname = ::File.join(__dir__, '../README.md')
zname = 'test/data/generated/README.zip'
Zip::File.open(zname, Zip::File::CREATE) do |zipfile|
zipfile.get_output_stream(File.basename(fname)) do |f|

View File

@ -1,5 +1,7 @@
require 'test_helper'
require 'forwardable'
class ZipInputStreamTest < MiniTest::Test
include AssertEntry
@ -134,7 +136,7 @@ class ZipInputStreamTest < MiniTest::Test
assert_equal(TestZipFile::TEST_ZIP2.entry_names[0], e.name)
# Do a little reading
buf = ''
buf = ''.b
buf << zis.read(100)
assert_equal(100, zis.pos)
buf << (zis.gets || '')
@ -143,7 +145,7 @@ class ZipInputStreamTest < MiniTest::Test
zis.rewind
buf2 = ''
buf2 = ''.b
buf2 << zis.read(100)
buf2 << (zis.gets || '')
buf2 << (zis.gets || '')

View File

@ -8,7 +8,7 @@ class AbstractOutputStreamTest < MiniTest::Test
attr_accessor :buffer
def initialize
@buffer = ''
@buffer = ''.b
end
def <<(data)
@ -58,12 +58,12 @@ class AbstractOutputStreamTest < MiniTest::Test
assert_equal("hello world. You ok out there?\nI sure hope so!\n", @output_stream.buffer)
$, = 'X'
@output_stream.buffer = ''
@output_stream.buffer = ''.b
@output_stream.print('monkey', 'duck', 'zebra')
assert_equal("monkeyXduckXzebra\n", @output_stream.buffer)
$\ = nil
@output_stream.buffer = ''
@output_stream.buffer = ''.b
@output_stream.print(20)
assert_equal('20', @output_stream.buffer)
end
@ -87,19 +87,19 @@ class AbstractOutputStreamTest < MiniTest::Test
@output_stream.puts('hello', 'world')
assert_equal("\nhello\nworld\n", @output_stream.buffer)
@output_stream.buffer = ''
@output_stream.buffer = ''.b
@output_stream.puts("hello\n", "world\n")
assert_equal("hello\nworld\n", @output_stream.buffer)
@output_stream.buffer = ''
@output_stream.buffer = ''.b
@output_stream.puts(%W[hello\n world\n])
assert_equal("hello\nworld\n", @output_stream.buffer)
@output_stream.buffer = ''
@output_stream.buffer = ''.b
@output_stream.puts(%W[hello\n world\n], 'bingo')
assert_equal("hello\nworld\nbingo\n", @output_stream.buffer)
@output_stream.buffer = ''
@output_stream.buffer = ''.b
@output_stream.puts(16, 20, 50, 'hello')
assert_equal("16\n20\n50\nhello\n", @output_stream.buffer)
end

View File

@ -23,7 +23,7 @@ class ZipOutputStreamTest < MiniTest::Test
end
def test_write_buffer
io = ::StringIO.new('')
io = ::StringIO.new
buffer = ::Zip::OutputStream.write_buffer(io) do |zos|
zos.comment = TEST_ZIP.comment
write_test_zip(zos)
@ -33,7 +33,7 @@ class ZipOutputStreamTest < MiniTest::Test
end
def test_write_buffer_binmode
io = ::StringIO.new('')
io = ::StringIO.new
buffer = ::Zip::OutputStream.write_buffer(io) do |zos|
zos.comment = TEST_ZIP.comment
write_test_zip(zos)

View File

@ -1,4 +1,3 @@
require 'simplecov'
require 'minitest/autorun'
require 'minitest/unit'
require 'fileutils'
@ -146,7 +145,7 @@ module CrcTest
attr_accessor :buffer
def initialize
@buffer = ''
@buffer = ''.b
end
def <<(data)
@ -223,3 +222,21 @@ module ZipEntryData
TEST_ISDIRECTORY = false
TEST_TIME = Time.now
end
module ZipV3Assertions
def assert_v3_api_warning
env_save = ENV['RUBYZIP_V3_API_WARN']
ENV['RUBYZIP_V3_API_WARN'] = '1'
assert_output('', /^You have called/) { yield }
ensure
ENV['RUBYZIP_V3_API_WARN'] = env_save
end
def refute_v3_api_warning
env_save = ENV['RUBYZIP_V3_API_WARN']
ENV['RUBYZIP_V3_API_WARN'] = '1'
assert_output('', '') { yield }
ensure
ENV['RUBYZIP_V3_API_WARN'] = env_save
end
end

283
test/version_3_api_test.rb Normal file
View File

@ -0,0 +1,283 @@
require 'test_helper'
module Version3APITest
class ZipFileTest < MiniTest::Test
include CommonZipFileFixture
include ZipV3Assertions
def test_new
assert_v3_api_warning do
file = ::Zip::File.new(TEST_ZIP.zip_name, true, false, restore_times: true) {}
assert(file.restore_times)
refute(file.restore_permissions)
end
assert_v3_api_warning do
string_io = StringIO.new(File.read('test/data/rubycode.zip'))
file = ::Zip::File.new(string_io, false, true, restore_times: true) {}
assert(file.restore_times)
refute(file.restore_permissions)
end
refute_v3_api_warning do
file = ::Zip::File.new(TEST_ZIP.zip_name, create: true, restore_times: true) {}
assert(file.restore_times)
refute(file.restore_permissions)
end
refute_v3_api_warning do
string_io = StringIO.new(File.read('test/data/rubycode.zip'))
file = ::Zip::File.new(string_io, buffer: true, restore_times: true) {}
assert(file.restore_times)
refute(file.restore_permissions)
end
end
def test_open
refute_v3_api_warning do
file = ::Zip::File.open('test/data/rubycode.zip', restore_permissions: true)
assert(file.restore_permissions)
refute(file.restore_times)
file.close
end
assert_v3_api_warning do
file = ::Zip::File.open(TEST_ZIP.zip_name, true, restore_permissions: true)
assert(file.restore_permissions)
refute(file.restore_times)
file.close
end
refute_v3_api_warning do
file = ::Zip::File.open(TEST_ZIP.zip_name, create: true, restore_permissions: true)
assert(file.restore_permissions)
refute(file.restore_times)
file.close
end
end
def test_add_buffer
assert_v3_api_warning do
Zip::File.add_buffer {}
end
end
def test_get_output_stream
refute_v3_api_warning do
zf = ::Zip::File.new(EMPTY_FILENAME, create: true)
zf.get_output_stream('myFile') { |os| os.write 'myFile contains just this' }
zf.close
end
assert_v3_api_warning do
zf = ::Zip::File.new(EMPTY_FILENAME, create: true)
zf.get_output_stream('myFile', 0o644) { |os| os.write 'myFile contains just this' }
zf.close
end
end
end
class ZipEntryTest < MiniTest::Test
include ZipEntryData
include ZipV3Assertions
def test_v3_constructor_and_getters
refute_v3_api_warning do
entry = ::Zip::Entry.new(TEST_ZIPFILE,
TEST_NAME,
comment: TEST_COMMENT,
extra: TEST_EXTRA,
compressed_size: TEST_COMPRESSED_SIZE,
crc: TEST_CRC,
compression_method: TEST_COMPRESSIONMETHOD,
size: TEST_SIZE,
time: TEST_TIME)
assert_equal(TEST_COMMENT, entry.comment)
assert_equal(TEST_COMPRESSED_SIZE, entry.compressed_size)
assert_equal(TEST_CRC, entry.crc)
assert_instance_of(::Zip::ExtraField, entry.extra)
assert_equal(TEST_COMPRESSIONMETHOD, entry.compression_method)
assert_equal(TEST_NAME, entry.name)
assert_equal(TEST_SIZE, entry.size)
assert_equal(TEST_TIME, entry.time)
end
end
def test_basic_constructor
refute_v3_api_warning do
::Zip::Entry.new(TEST_ZIPFILE, TEST_NAME)
end
end
def test_v2_constructor_and_getters
assert_v3_api_warning do
entry = ::Zip::Entry.new(TEST_ZIPFILE,
TEST_NAME,
TEST_COMMENT,
TEST_EXTRA,
TEST_COMPRESSED_SIZE,
TEST_CRC,
TEST_COMPRESSIONMETHOD,
TEST_SIZE,
TEST_TIME)
assert_equal(TEST_COMMENT, entry.comment)
assert_equal(TEST_COMPRESSED_SIZE, entry.compressed_size)
assert_equal(TEST_CRC, entry.crc)
assert_instance_of(::Zip::ExtraField, entry.extra)
assert_equal(TEST_COMPRESSIONMETHOD, entry.compression_method)
assert_equal(TEST_NAME, entry.name)
assert_equal(TEST_SIZE, entry.size)
assert_equal(TEST_TIME, entry.time)
end
end
end
class ZipInputStreamTest < MiniTest::Test
include ZipV3Assertions
def test_new_with_old_offset
assert_v3_api_warning do
zis = ::Zip::InputStream.new(TestZipFile::TEST_ZIP2.zip_name, 100)
assert_equal(100, zis.instance_variable_get(:@archive_io).pos)
zis.close
end
end
def test_new_with_new_offset
refute_v3_api_warning do
zis = ::Zip::InputStream.new(TestZipFile::TEST_ZIP2.zip_name, offset: 100)
assert_equal(100, zis.instance_variable_get(:@archive_io).pos)
zis.close
end
end
def test_new_with_clashing_offset
assert_v3_api_warning do
zis = ::Zip::InputStream.new(TestZipFile::TEST_ZIP2.zip_name, 10, offset: 100)
assert_equal(100, zis.instance_variable_get(:@archive_io).pos)
zis.close
end
end
def test_open
refute_v3_api_warning do
::Zip::InputStream.open(TestZipFile::TEST_ZIP2.zip_name) {}
end
refute_v3_api_warning do
::Zip::InputStream.open(TestZipFile::TEST_ZIP2.zip_name, decrypter: true) {}
end
assert_v3_api_warning do
::Zip::InputStream.open(TestZipFile::TEST_ZIP2.zip_name, 100, nil) {}
end
end
def test_open_buffer
assert_v3_api_warning do
::Zip::InputStream.open_buffer(StringIO.new)
end
end
end
class ZipOutputStreamTest < MiniTest::Test
include ZipV3Assertions
TEST_ZIP = TestZipFile::TEST_ZIP2.clone
TEST_ZIP.zip_name = 'test/data/generated/output.zip'
def test_new
refute_v3_api_warning do
::Zip::OutputStream.new(TEST_ZIP.zip_name)
end
refute_v3_api_warning do
::Zip::OutputStream.new(StringIO.new, stream: true)
end
assert_v3_api_warning do
::Zip::OutputStream.new(StringIO.new, true)
end
refute_v3_api_warning do
::Zip::OutputStream.new(TEST_ZIP.zip_name, stream: false, encrypter: true)
end
assert_v3_api_warning do
::Zip::OutputStream.new(TEST_ZIP.zip_name, false, true)
end
end
def test_open
refute_v3_api_warning do
::Zip::OutputStream.open(TEST_ZIP.zip_name) {}
end
refute_v3_api_warning do
::Zip::OutputStream.open(TEST_ZIP.zip_name, encrypter: true) {}
end
assert_v3_api_warning do
::Zip::OutputStream.open(TEST_ZIP.zip_name, true) {}
end
end
def test_write_buffer
refute_v3_api_warning do
::Zip::OutputStream.write_buffer(StringIO.new) {}
end
refute_v3_api_warning do
::Zip::OutputStream.write_buffer(StringIO.new, encrypter: true) {}
end
assert_v3_api_warning do
::Zip::OutputStream.write_buffer(StringIO.new, true) {}
end
end
end
class ZipFileSplitTest < MiniTest::Test
include ZipV3Assertions
TEST_ZIP = TestZipFile::TEST_ZIP2.clone
TEST_ZIP.zip_name = 'large_zip_file.zip'
def setup
FileUtils.cp(TestZipFile::TEST_ZIP2.zip_name, TEST_ZIP.zip_name)
end
def teardown
File.delete(TEST_ZIP.zip_name)
Dir["#{TEST_ZIP.zip_name}.*"].each do |zip_file_name|
File.delete(zip_file_name) if File.exist?(zip_file_name)
end
end
def test_old_split
assert_v3_api_warning do
Zip::File.split(TEST_ZIP.zip_name, 65_536, false)
end
end
def test_new_split
refute_v3_api_warning do
Zip::File.split(TEST_ZIP.zip_name, segment_size: 65_536, delete_zip_file: false)
end
end
end
class ZipDOSTimeTest < MiniTest::Test
include ZipV3Assertions
def test_dos_equals
assert_v3_api_warning do
time = ::Zip::DOSTime.now
assert(time.dos_equals(time))
end
end
end
end