Skip to content

Commit

Permalink
Selectable checksums and matching tests
Browse files Browse the repository at this point in the history
Note: the initializer is removed here, because it *does nothing*.
If all a method does is call `super` with the same args, it is better
for it not to exist.
  • Loading branch information
jmartin-sul authored and atz committed Apr 7, 2018
1 parent 4de93ed commit 7c17e40
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 20 deletions.
52 changes: 32 additions & 20 deletions lib/moab/file_signature.rb
Expand Up @@ -44,11 +44,6 @@ class FileSignature < Serializer::Serializable
# The name of the XML element used to serialize this objects data
tag 'fileSignature'

# (see Serializable#initialize)
def initialize(opts = {})
super(opts)
end

# @attribute
# @return [Integer] The size of the file in bytes
attribute :size, Integer, :on_save => Proc.new { |n| n.to_s }
Expand All @@ -65,6 +60,30 @@ def initialize(opts = {})
# @return [String] The SHA256 checksum value of the file
attribute :sha256, String, :on_save => Proc.new { |n| n.nil? ? "" : n.to_s }

KNOWN_ALGOS = {
md5: proc { Digest::MD5.new },
sha1: proc { Digest::SHA1.new },
sha256: proc { Digest::SHA2.new(256) }
}.freeze

# Reads the file once for ALL (requested) algorithms, not once per.
# @param [Pathname] pathname
# @param [Array<Symbol>] one or more keys of KNOWN_ALGOS to be computed
# @return [Moab::FileSignature] object populated with (requested) checksums
def self.from_file(pathname, algos_to_use = KNOWN_ALGOS.keys)
raise 'Unrecognized algorithm requested' unless algos_to_use.all? { |a| KNOWN_ALGOS.include?(a) }

signatures = algos_to_use.map { |k| [k, KNOWN_ALGOS[k].call] }.to_h

pathname.open("r") do |stream|
while (buffer = stream.read(8192))
signatures.each_value { |digest| digest.update(buffer) }
end
end

new(signatures.map { |k, digest| [k, digest.hexdigest] }.to_h.merge(size: pathname.size) )
end

# @param type [Symbol,String] The type of checksum
# @param value [String] The checksum value
# @return [void] Set the value of the specified checksum type
Expand Down Expand Up @@ -139,24 +158,17 @@ def hash
@size.to_i
end

# @api internal
# @deprecated
# this method is a holdover from an earlier version. use the class method .from_file going forward.
# @api external
# @param pathname [Pathname] The location of the file to be digested
# @return [FileSignature] Generate a FileSignature instance containing size and checksums for a physical file
def signature_from_file(pathname)
@size = pathname.size
md5_digest = Digest::MD5.new
sha1_digest = Digest::SHA1.new
sha256_digest = Digest::SHA2.new(256)
pathname.open("r") do |stream|
while (buffer = stream.read(8192))
md5_digest.update(buffer)
sha1_digest.update(buffer)
sha256_digest.update(buffer)
end
end
@md5 = md5_digest.hexdigest
@sha1 = sha1_digest.hexdigest
@sha256 = sha256_digest.hexdigest
file_signature = self.class.from_file(pathname)
@size = file_signature.size
@md5 = file_signature.md5
@sha1 = file_signature.sha1
@sha256 = file_signature.sha256
self
end

Expand Down
18 changes: 18 additions & 0 deletions spec/unit_tests/moab/file_signature_spec.rb
Expand Up @@ -14,6 +14,24 @@
described_class.new.signature_from_file(page1_v2_pathname)
end

describe '.from_file' do
it 'raises if unrecognized checksum requested' do
expect { described_class.from_file('whatever', [:rot13]) }.to raise_exception /Unrecognized algorithm/
end
it 'computes all checksums by default' do
sig = described_class.from_file(title_v1_pathname)
expect(sig.md5).to eq '1a726cd7963bd6d3ceb10a8c353ec166'
expect(sig.sha1).to eq '583220e0572640abcd3ddd97393d224e8053a6ad'
expect(sig.sha256).to eq '8b0cee693a3cf93cf85220dd67c5dc017a7edcdb59cde8fa7b7f697be162b0c5'
end
it 'only computes requested checksum(s)' do
sig = described_class.from_file(title_v1_pathname, [:md5, :sha1])
expect(sig.md5).to eq '1a726cd7963bd6d3ceb10a8c353ec166'
expect(sig.sha1).to eq '583220e0572640abcd3ddd97393d224e8053a6ad'
expect(sig.sha256).to be_nil
end
end

specify '#initialize' do
opts = {
size: 75,
Expand Down

0 comments on commit 7c17e40

Please sign in to comment.