defmodule Mv.Authorization.RoleTest do @moduledoc """ Unit tests for Role resource validations and constraints. """ use Mv.DataCase, async: true alias Mv.Authorization describe "permission_set_name validation" do test "accepts valid permission set names" do attrs = %{ name: "Test Role", permission_set_name: "own_data" } assert {:ok, role} = Authorization.create_role(attrs) assert role.permission_set_name == "own_data" end test "rejects invalid permission set names" do attrs = %{ name: "Test Role", permission_set_name: "invalid_set" } assert {:error, %Ash.Error.Invalid{errors: errors}} = Authorization.create_role(attrs) assert error_message(errors, :permission_set_name) =~ "must be one of" end test "accepts all four valid permission sets" do valid_sets = ["own_data", "read_only", "normal_user", "admin"] for permission_set <- valid_sets do attrs = %{ name: "Role #{permission_set}", permission_set_name: permission_set } assert {:ok, _role} = Authorization.create_role(attrs) end end end describe "system role deletion protection" do test "prevents deletion of system roles" do # is_system_role is not settable via public API, so we use Ash.Changeset directly changeset = Mv.Authorization.Role |> Ash.Changeset.for_create(:create_role, %{ name: "System Role", permission_set_name: "own_data" }) |> Ash.Changeset.force_change_attribute(:is_system_role, true) {:ok, system_role} = Ash.create(changeset) assert {:error, %Ash.Error.Invalid{errors: errors}} = Authorization.destroy_role(system_role) message = error_message(errors, :is_system_role) assert message =~ "Cannot delete system role" end test "allows deletion of non-system roles" do # is_system_role defaults to false, so regular create works {:ok, regular_role} = Authorization.create_role(%{ name: "Regular Role", permission_set_name: "read_only" }) assert :ok = Authorization.destroy_role(regular_role) end end describe "name uniqueness" do test "enforces unique role names" do attrs = %{ name: "Unique Role", permission_set_name: "own_data" } assert {:ok, _} = Authorization.create_role(attrs) assert {:error, %Ash.Error.Invalid{errors: errors}} = Authorization.create_role(attrs) assert error_message(errors, :name) =~ "has already been taken" end end # Helper function for error evaluation defp error_message(errors, field) when is_atom(field) do errors |> Enum.filter(fn err -> Map.get(err, :field) == field end) |> Enum.map(&Map.get(&1, :message, "")) |> List.first() || "" end end