3.1 KiB · text History b868907
defmodule GitGud.Repositories.LicenseDetectionTest do
  @moduledoc """
  Reading a licence out of a real git repository and recording it.

  Only the root tree is scanned, and only files that look like a
  licence are read — a repository is not searched for one.
  """
  use GitGud.DataCase, async: false

  import GitGud.ForgeFixtures

  alias GitGud.Repositories
  alias GitGud.Repositories.Repository

  setup do
    {user, repo} = repository_fixture()
    seed_main_branch(repo, user)
    %{user: user, repo: repo}
  end

  defp reload(repo), do: GitGud.Repo.get!(Repository, repo.id)

  test "records the licence at the tip of the default branch", %{repo: repo, user: user} do
    sha = seed_file(repo, "main", "LICENSE.md", File.read!("LICENSE.md"), user)

    assert {:ok, "AGPL-3.0"} = Repositories.detect_and_store_license(repo, sha)

    stored = reload(repo)
    assert stored.license == "AGPL-3.0"
    assert stored.license_file == "LICENSE.md"
  end

  test "a repository with no licence file records none", %{repo: repo} do
    {:ok, sha} = GitGud.Git.resolve(repo.disk_path, "refs/heads/main")

    assert {:ok, nil} = Repositories.detect_and_store_license(repo, sha)

    stored = reload(repo)
    assert stored.license == nil
    assert stored.license_file == nil
  end

  test "an unrecognised licence file is nil rather than a guess", %{repo: repo, user: user} do
    sha = seed_file(repo, "main", "LICENSE", "You may use this if you are nice to me.\n", user)

    assert {:ok, nil} = Repositories.detect_and_store_license(repo, sha)
    assert reload(repo).license == nil
  end

  test "clears a licence that the tip no longer carries", %{repo: repo, user: user} do
    licensed = seed_file(repo, "main", "LICENSE", File.read!("LICENSE.md"), user)
    assert {:ok, "AGPL-3.0"} = Repositories.detect_and_store_license(repo, licensed)

    # The file is still there in history, and gone from the tree that
    # matters — detection follows HEAD, not the past.
    removed = seed_file(repo, "main", "LICENSE", "no longer a licence\n", user)

    assert {:ok, nil} = Repositories.detect_and_store_license(repo, removed)
    assert reload(repo).license == nil
  end

  test "doesn't read a file that merely mentions one", %{repo: repo, user: user} do
    sha =
      seed_file(
        repo,
        "main",
        "README.md",
        "Licensed under the GNU General Public License v3",
        user
      )

    assert {:ok, nil} = Repositories.detect_and_store_license(repo, sha)
  end

  describe "backfill" do
    test "walks every repository and reports what it found", %{repo: repo, user: user} do
      seed_file(repo, "main", "LICENSE", File.read!("LICENSE.md"), user)

      {:ok, reports} = Agent.start_link(fn -> [] end)

      {seen, detected} =
        Repositories.backfill_licenses(on_repo: &Agent.update(reports, fn acc -> [&1 | acc] end))

      assert seen >= 1
      assert detected >= 1
      assert reload(repo).license == "AGPL-3.0"

      assert Enum.any?(Agent.get(reports, & &1), fn report ->
               report.repository.id == repo.id and report.license == "AGPL-3.0"
             end)
    end
  end
end