2.5 KiB · text History b868907
defmodule GitGud.Packages.Fdroid.ArscTest do
  @moduledoc """
  The `resources.arsc` reader.

  What makes this worth having: `android:icon` is a resource id, and in
  a release build there is nothing else left to go on — R8 renames
  `res/mipmap-xxxhdpi/ic_launcher.png` to `res/o-.png`. Resolving the
  id is the only route to the icon, so the ranking rules are as
  load-bearing as the parsing.
  """
  use ExUnit.Case, async: true

  alias GitGud.ApkFixtures
  alias GitGud.Packages.Formats.Fdroid.Arsc

  @icon 0x7F010000
  @label 0x7F020000

  describe "parsing" do
    test "reads a table's packages and entries" do
      assert {:ok, table} = Arsc.parse(ApkFixtures.resources_arsc())
      assert map_size(table.entries) == 2
    end

    test "refuses input that isn't a resource table" do
      assert {:error, {422, _}} = Arsc.parse("not an arsc at all")
      assert {:error, {422, _}} = Arsc.parse(<<>>)
    end

    test "refuses a table that claims to be longer than it is" do
      <<head::binary-size(4), _size::little-32, rest::binary>> = ApkFixtures.resources_arsc()
      truncated = head <> <<999_999::little-32>> <> rest

      assert {:error, {422, message}} = Arsc.parse(truncated)
      assert message =~ "truncated"
    end

    test "survives arbitrary truncation rather than raising" do
      arsc = ApkFixtures.resources_arsc()

      for len <- 1..byte_size(arsc)//7 do
        case Arsc.parse(binary_part(arsc, 0, len)) do
          {:ok, table} -> assert is_map(table.entries)
          {:error, {422, _}} -> :ok
        end
      end
    end
  end

  describe "file_paths/2" do
    setup do
      {:ok, table} = Arsc.parse(ApkFixtures.resources_arsc())
      %{table: table}
    end

    test "ranks the highest density first", %{table: table} do
      assert ["res/hi.png" | rest] = Arsc.file_paths(table, @icon)
      assert "res/lo.png" in rest
    end

    test "puts adaptive-icon XML last", %{table: table} do
      paths = Arsc.file_paths(table, @icon)

      assert List.last(paths) == "res/ad.xml"
    end

    test "is empty for an id the table doesn't define", %{table: table} do
      assert Arsc.file_paths(table, 0x7F990000) == []
      assert Arsc.file_paths(table, 0) == []
    end
  end

  describe "string/2" do
    test "resolves a label" do
      {:ok, table} = Arsc.parse(ApkFixtures.resources_arsc())

      assert Arsc.string(table, @label) == "GitGud"
    end

    test "is nil for an unknown id" do
      {:ok, table} = Arsc.parse(ApkFixtures.resources_arsc())

      assert Arsc.string(table, 0x7F990000) == nil
    end
  end
end