2.0 KiB · text History b299654
defmodule GitGud.Packages.Fdroid.ZipTest do
  @moduledoc """
  Reading one member out of an APK.

  The case that matters is the one Erlang's own reader can't do:
  `zipalign` pads stored entries with an extra field that isn't a
  well-formed extra field, and `:zip.unzip/2` raises a `function_clause`
  on it. Every PNG in a release APK is stored and padded that way — the
  icon included — so this test asserts against the failure rather than
  around it.
  """
  use ExUnit.Case, async: true

  alias GitGud.ApkFixtures
  alias GitGud.Packages.Formats.Fdroid.Zip

  @png <<0x89, "PNG", 0x0D, 0x0A, 0x1A, 0x0A, "pretend this is pixels">>

  test "reads a stored entry that :zip.unzip refuses" do
    archive = ApkFixtures.aligned_zip("res/o-.png", @png)

    # The behaviour this module exists for. If Erlang ever fixes it,
    # this assertion is the thing that says so.
    assert :error == elem(:zip.unzip(archive, [:memory, {:file_list, [~c"res/o-.png"]}]), 0)

    assert {:ok, @png} = Zip.read(archive, "res/o-.png")
  end

  test "reads a deflated entry" do
    {:ok, {_, archive}} =
      :zip.create(~c"t.zip", [{~c"AndroidManifest.xml", :binary.copy("compress me", 50)}], [
        :memory
      ])

    assert {:ok, bytes} = Zip.read(archive, "AndroidManifest.xml")
    assert bytes == :binary.copy("compress me", 50)
  end

  test "lists names" do
    archive = ApkFixtures.aligned_zip("res/o-.png", @png)

    assert Zip.names(archive) == ["res/o-.png"]
  end

  test "is :none for a member that isn't there, and for rubbish" do
    archive = ApkFixtures.aligned_zip("res/o-.png", @png)

    assert Zip.read(archive, "res/nope.png") == :none
    assert Zip.read("not a zip", "anything") == :none
    assert Zip.names("not a zip") == []
  end

  test "is :none when a member claims to run past the end of the archive" do
    archive = ApkFixtures.aligned_zip("res/o-.png", @png)

    assert Zip.read(binary_part(archive, 0, byte_size(archive) - 40), "res/o-.png") == :none
  end
end