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 {:ok, system_role} = Authorization.create_role(%{ name: "System Role", permission_set_name: "own_data", is_system_role: true }) assert {:error, %Ash.Error.Invalid{errors: errors}} = Authorization.destroy_role(system_role) message = error_message(errors, nil) assert message =~ "Cannot delete system role" end test "allows deletion of non-system roles" do {:ok, regular_role} = Authorization.create_role(%{ name: "Regular Role", permission_set_name: "read_only", is_system_role: false }) 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 # When field is nil, returns first error message (for errors without specific field) defp error_message(errors, field) when is_nil(field) do errors |> Enum.map(&Map.get(&1, :message, "")) |> List.first() || "" end defp error_message(errors, field) do errors |> Enum.filter(fn err -> Map.get(err, :field) == field end) |> Enum.map(&Map.get(&1, :message, "")) |> List.first() || "" end end