Currently what I am doing:
:zip.t
and :zip.tt
let it list down the contents of the zip folder to see if it's what I am expecting. Somehow I think I am missing something. Is it better to test with :zip.table
? The function looks confusing. Can someone provide an example of how to use it ? Below is an example of the output I got to, but I can't figure out how to make this into a test ? Is md5sum a better test for zip archives ?
iex(4)> :zip.table('testing.zip')
{:ok,
[{:zip_comment, []},
{:zip_file, 'mix.exs',
{:file_info, 930, :regular, :read_write, {{2015, 7, 15}, {2, 11, 9}},
{{2015, 7, 15}, {2, 11, 9}}, {{2015, 7, 15}, {2, 11, 9}}, 54, 1, 0, 0, 0, 0,
0}, [], 0, 444},
{:zip_file, 'mix.lock',
{:file_info, 332, :regular, :read_write, {{2015, 7, 15}, {2, 9, 6}},
{{2015, 7, 15}, {2, 9, 6}}, {{2015, 7, 15}, {2, 9, 6}}, 54, 1, 0, 0, 0, 0,
0}, [], 481, 152}]}
The :zip
module from Erlang is not really easy to work with, I'll try to break it down for you.
First, we will need an appropriate representation of the zip_file
record in order from Erlang to be able to properly work with it. Otherwise, we would have to do matches on tuples with a lot of elements which would just clutter our code unnecessarily. The following module is heavily based on the File.Stat
implementation from Elixir and will allow us to access the values in those unwieldy tuples with simple dot notation.
require Record
defmodule Zip.File do
record = Record.extract(:zip_file, from_lib: "stdlib/include/zip.hrl")
keys = :lists.map(&elem(&1, 0), record)
vals = :lists.map(&{&1, [], nil}, keys)
pairs = :lists.zip(keys, vals)
defstruct keys
def to_record(%Zip.File{unquote_splicing(pairs)}) do
{:zip_file, unquote_splicing(vals)}
end
def from_record(zip_file)
def from_record({:zip_file, unquote_splicing(vals)}) do
%Zip.File{unquote_splicing(pairs)}
|> Map.update!(:info, fn(info) -> File.Stat.from_record(info) end)
end
end
We can now build a small wrapper class around the Erlang zip
module. It does not wrap all methods, just the ones we'll use here. I also added a list_files/1
function that only returns files, excluding directories and comments from the listing.
defmodule Zip do
def open(archive) do
{:ok, zip_handle} = :zip.zip_open(archive)
zip_handle
end
def close(zip_handle) do
:zip.zip_close(zip_handle)
end
def list_dir(zip_handle) do
{:ok, result} = :zip.zip_list_dir(zip_handle)
result
end
def list_files(zip_handle) do
list_dir(zip_handle)
|> Enum.drop(1)
|> Enum.map(&Zip.File.from_record/1)
|> Enum.filter(&(&1.info.type == :regular))
end
end
Suppose we have the following zip archive for testing:
cd /tmp
touch foo bar baz
zip archive.zip foo bar baz
Now you can assert the file names inside the zip archive:
test "files are in zip" do
zip = Zip.open('/tmp/archive.zip')
files = Zip.list_files(zip) |> Enum.map(&(&1.name))
Zip.close(zip)
assert files == ['foo', 'bar', 'baz']
end
I'll leave further operations and assertions on the zip archive for you to implement, and hope this gets you started.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With