Skip to content

Conversation

cosmo0920
Copy link
Contributor

With this repro which is based on #112 (comment)

require "digest"
require "tempfile"

$LOAD_PATH.unshift File.expand_path('lib', __dir__)
require 'zstd-ruby'

puts "Zstd::VERSION=#{Zstd::VERSION}"

def compare_compressed(original:, compressed:)
  begin
    decompressed = Zstd.decompress(compressed)
  rescue => e
    decompress_error = e
  end

  if original != decompressed
    if decompress_error
      puts "Decompression error for #{original.bytesize} bytes input (#{decompress_error})"
    else
      puts "Content mismatch for #{original.bytesize} bytes input"
    end

    puts "  Original:        #{original.bytesize} bytes, #{Digest::SHA256.hexdigest(original)[0, 10]} checksum"

    if decompressed
      puts "  Zstd.decompress: #{decompressed.bytesize} bytes, #{Digest::SHA256.hexdigest(decompressed)[0, 10]} checksum"
    end

    begin
      cli_decompressed = Tempfile.create(binmode: true) do |temp_write|
        temp_write.write(compressed)
        temp_write.close
        Tempfile.create(binmode: true) do |temp_read|
          system "zstd", "--decompress", "--quiet", "--force", "-o", temp_read.path, temp_write.path, exception: true
          File.read(temp_read.path, binmode: true)
        end
      end

      puts "  zstd cli:        #{cli_decompressed.bytesize} bytes, #{Digest::SHA256.hexdigest(cli_decompressed)[0, 10]} checksum"
    rescue => e
      puts "  zstd cli error: #{e}"
    end
  end
end

def test_stream_write
  (1..256_000).each do |length|
    original = "a" * length

    stream = Zstd::StreamingCompress.new
    stream << original
    res = stream.finish

    compare_compressed(original: original, compressed: res)
  end
end

def test_stream_compress
  (1..256_000).each do |length|
    original = "a" * length

    stream = Zstd::StreamingCompress.new
    res = stream.compress(original)
    res << stream.finish

    compare_compressed(original: original, compressed: res)
  end
end

def test_compress
  (1..256_000).each do |length|
    original = "a" * length

    res = Zstd.compress(original)

    compare_compressed(original: original, compressed: res)
  end
end

def debug_specific_size(length)
  puts "=== Debugging size #{length} ==="
  original = "a" * length

  # 1. Generate the "good" stream using the working .compress method
  stream_good = Zstd::StreamingCompress.new
  good_compressed = stream_good.compress(original)
  good_compressed << stream_good.finish
  File.write("good.zst", good_compressed)
  puts "Saved working output to good.zst (#{good_compressed.bytesize} bytes)"

  # 2. Generate the "bad" stream using the failing << method
  stream_bad = Zstd::StreamingCompress.new
  stream_bad << original
  bad_compressed = stream_bad.finish
  File.write("bad.zst", bad_compressed)
  puts "Saved failing output to bad.zst (#{bad_compressed.bytesize} bytes)"
  puts
end

case ARGV[0]
when "stream_write"
  puts "=== Zstd::StreamingCompress.new with << ==="
  test_stream_write
when "stream_compress"
  puts "=== Zstd::StreamingCompress.new with .compress ==="
  test_stream_compress
when "compress"
  puts "=== Zstd.compress ==="
  test_compress
when "debug"
  size = ARGV[1].to_i
  if size <= 0
    abort "Please provide a specific size to debug, e.g., 'ruby zstd_repro.rb debug 20086'"
  end
  debug_specific_size(size)
else
  abort "Unknown test mode: #{ARGV[0].inspect}"
end

And using with rspec tests, there is no issues and checksum mismatches reported.

$ bundle exec rspec

<snip>
Finished in 15.39 seconds (files took 0.12929 seconds to load)
60 examples, 0 failures
% ruby zstd_repro.rb compress
Zstd::VERSION=2.0.0
=== Zstd.compress ===
% ruby zstd_repro.rb stream_compress
Zstd::VERSION=2.0.0
=== Zstd::StreamingCompress.new with .compress ===
% ruby zstd_repro.rb stream_write
Zstd::VERSION=2.0.0
=== Zstd::StreamingCompress.new with << ===

Signed-off-by: Hiroshi Hatake <cosmo0920.oucc@gmail.com>
Signed-off-by: Hiroshi Hatake <cosmo0920.oucc@gmail.com>
Signed-off-by: Hiroshi Hatake <cosmo0920.oucc@gmail.com>
Signed-off-by: Hiroshi Hatake <cosmo0920.oucc@gmail.com>
Signed-off-by: Hiroshi Hatake <cosmo0920.oucc@gmail.com>
Signed-off-by: Hiroshi Hatake <cosmo0920.oucc@gmail.com>
Signed-off-by: Hiroshi Hatake <cosmo0920.oucc@gmail.com>
Signed-off-by: Hiroshi Hatake <cosmo0920.oucc@gmail.com>
Signed-off-by: Hiroshi Hatake <cosmo0920.oucc@gmail.com>
@SpringMT
Copy link
Owner

Thank you!

@SpringMT SpringMT merged commit 8f272d9 into SpringMT:main Sep 27, 2025
6 checks passed
@cosmo0920 cosmo0920 deleted the fix-checksum-mismatch branch September 28, 2025 00:40
@SpringMT
Copy link
Owner

I just released v2.0.1 !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants