6.9 KiB · text 5af55d9
defmodule GitGud.ProfilesTest do
use GitGud.DataCase, async: false
alias GitGud.Profiles
import GitGud.AccountsFixtures
import GitGud.ForgeFixtures
describe "pin/2" do
test "appends a new pin at the end" do
user = user_fixture()
{_, a} = repository_fixture(%{owner: user})
{_, b} = repository_fixture(%{owner: user})
{:ok, p1} = Profiles.pin(user, a)
{:ok, p2} = Profiles.pin(user, b)
assert p1.position == 0
assert p2.position == 1
ids_in_order = Profiles.list_pins(user) |> Enum.map(& &1.id)
assert ids_in_order == [p1.id, p2.id]
end
test "blocks the 8th pin" do
user = user_fixture()
repos =
for _ <- 1..(Profiles.max_pins() + 1) do
{_, repo} = repository_fixture(%{owner: user})
repo
end
{pinning, [last]} = Enum.split(repos, Profiles.max_pins())
for r <- pinning, do: {:ok, _} = Profiles.pin(user, r)
assert {:error, :max_reached} = Profiles.pin(user, last)
end
test "duplicate pin → unique-constraint changeset error" do
user = user_fixture()
{_, repo} = repository_fixture(%{owner: user})
{:ok, _} = Profiles.pin(user, repo)
assert {:error, %Ecto.Changeset{}} = Profiles.pin(user, repo)
end
end
describe "unpin/2" do
test "removes the pin and compacts positions" do
user = user_fixture()
{_, a} = repository_fixture(%{owner: user})
{_, b} = repository_fixture(%{owner: user})
{_, c} = repository_fixture(%{owner: user})
{:ok, _} = Profiles.pin(user, a)
{:ok, _} = Profiles.pin(user, b)
{:ok, _} = Profiles.pin(user, c)
_ = Profiles.unpin(user, b)
positions = Profiles.list_pins(user) |> Enum.map(& &1.position)
assert positions == [0, 1]
ids = Profiles.list_pins(user) |> Enum.map(& &1.repository_id)
assert ids == [a.id, c.id]
end
end
describe "reorder/2" do
test "applies a new order; unknown ids dropped silently" do
user = user_fixture()
{_, a} = repository_fixture(%{owner: user})
{_, b} = repository_fixture(%{owner: user})
{_, c} = repository_fixture(%{owner: user})
{:ok, p1} = Profiles.pin(user, a)
{:ok, p2} = Profiles.pin(user, b)
{:ok, p3} = Profiles.pin(user, c)
:ok = Profiles.reorder(user, [p3.id, p1.id, 99_999_999, p2.id])
ordered_ids = Profiles.list_pins(user) |> Enum.map(& &1.repository_id)
assert ordered_ids == [c.id, a.id, b.id]
end
test "pins not in the order list keep their relative order at the end" do
user = user_fixture()
{_, a} = repository_fixture(%{owner: user})
{_, b} = repository_fixture(%{owner: user})
{_, c} = repository_fixture(%{owner: user})
{:ok, p1} = Profiles.pin(user, a)
{:ok, _p2} = Profiles.pin(user, b)
{:ok, _p3} = Profiles.pin(user, c)
# Move only p1 to the end of an explicit list; b + c should
# follow in their original relative order.
:ok = Profiles.reorder(user, [p1.id])
ordered_ids = Profiles.list_pins(user) |> Enum.map(& &1.repository_id)
assert ordered_ids == [a.id, b.id, c.id]
end
test "string ids work (from the JS hook payload)" do
user = user_fixture()
{_, a} = repository_fixture(%{owner: user})
{_, b} = repository_fixture(%{owner: user})
{:ok, p1} = Profiles.pin(user, a)
{:ok, p2} = Profiles.pin(user, b)
:ok = Profiles.reorder(user, [Integer.to_string(p2.id), Integer.to_string(p1.id)])
ordered_ids = Profiles.list_pins(user) |> Enum.map(& &1.repository_id)
assert ordered_ids == [b.id, a.id]
end
end
describe "org-member cleanup on removal" do
test "removing a user from an org unpins that user's pins of org repos" do
owner = user_fixture()
{:ok, org} = GitGud.Organizations.create_organization(owner, %{"handle" => "acme"})
member = user_fixture()
:ok = GitGud.Organizations.add_member(org, member, "member") |> elem(0) |> (&(if &1 == :ok, do: :ok, else: :ok)).()
{_, own_repo} = repository_fixture(%{owner: member})
org_repo =
%GitGud.Repositories.Repository{
name: "site",
visibility: "private",
owner_id: owner.id,
organization_id: org.id,
default_branch: "main",
disk_path: "/tmp/test_unused"
}
|> GitGud.Repo.insert!()
{:ok, _} = Profiles.pin(member, own_repo)
{:ok, _} = Profiles.pin(member, org_repo)
assert length(Profiles.list_pins(member)) == 2
:ok = GitGud.Organizations.remove_member(org, member)
remaining = Profiles.list_pins(member)
assert length(remaining) == 1
assert [%{repository_id: rid}] = remaining
assert rid == own_repo.id
end
test "removing a user doesn't touch other members' personal pins" do
owner = user_fixture()
{:ok, org} = GitGud.Organizations.create_organization(owner, %{"handle" => "acme2"})
other = user_fixture()
_ = GitGud.Organizations.add_member(org, other, "member")
org_repo =
%GitGud.Repositories.Repository{
name: "shared",
visibility: "private",
owner_id: owner.id,
organization_id: org.id,
default_branch: "main",
disk_path: "/tmp/test_unused2"
}
|> GitGud.Repo.insert!()
{:ok, _} = Profiles.pin(other, org_repo)
{:ok, _} = Profiles.pin(owner, org_repo)
removed = user_fixture()
_ = GitGud.Organizations.add_member(org, removed, "member")
:ok = GitGud.Organizations.remove_member(org, removed)
assert length(Profiles.list_pins(other)) == 1
assert length(Profiles.list_pins(owner)) == 1
end
end
describe "Repositories.list_pinnable_for_user/1" do
test "includes own + org-member repos, excludes others" do
user = user_fixture()
other = user_fixture()
{_, own_repo} = repository_fixture(%{owner: user})
{_, stranger_repo} = repository_fixture(%{owner: other})
{:ok, org} = GitGud.Organizations.create_organization(other, %{"handle" => "acme3"})
_ = GitGud.Organizations.add_member(org, user, "member")
org_repo =
%GitGud.Repositories.Repository{
name: "shared",
visibility: "private",
owner_id: other.id,
organization_id: org.id,
default_branch: "main",
disk_path: "/tmp/test_unused3"
}
|> GitGud.Repo.insert!()
ids = GitGud.Repositories.list_pinnable_for_user(user) |> Enum.map(& &1.id) |> MapSet.new()
assert MapSet.subset?(MapSet.new([own_repo.id, org_repo.id]), ids)
refute MapSet.member?(ids, stranger_repo.id)
end
end
describe "scoping" do
test "user A's pins don't show up for user B" do
user_a = user_fixture()
user_b = user_fixture()
{_, repo} = repository_fixture(%{owner: user_a})
{:ok, _} = Profiles.pin(user_a, repo)
assert Profiles.list_pins(user_b) == []
end
end
end