defmodule OpenApiSpex.TestAssertions do @moduledoc """ Defines helpers for testing API responses and examples against API spec schemas. """ import ExUnit.Assertions alias OpenApiSpex.Cast.Error alias OpenApiSpex.{Cast, OpenApi} @dialyzer {:no_match, assert_schema: 3} @doc """ Asserts that `value` conforms to the schema with title `schema_title` in `api_spec`. """ @spec assert_schema(term, String.t(), OpenApi.t(), Cast.read_write_scope()) :: term | no_return def assert_schema(value, schema_title, api_spec = %OpenApi{}, read_write_scope \\ nil) do schemas = api_spec.components.schemas schema = schemas[schema_title] if !schema do flunk("Schema: #{schema_title} not found in #{inspect(Map.keys(schemas))}") end cast_context = %Cast{ value: value, schema: schema, schemas: api_spec.components.schemas, read_write_scope: read_write_scope } assert_schema(cast_context) end @doc """ Asserts that `value` conforms to the schema in the given `%Cast{}` context. """ @spec assert_schema(Cast.t()) :: term def assert_schema(cast_context) do case Cast.cast(cast_context) do {:ok, data} -> data {:error, errors} -> schema = cast_context.schema errors = errors |> Enum.map(fn error -> message = Error.message(error) path = Error.path_to_string(error) "#{message} at #{path}" end) if Enum.any?(errors) do errors_info = Enum.join(errors, "\n") debug_info = "#{schema.title}: #{errors_info}\n#{inspect(cast_context.value)}" flunk("Value does not conform to schema #{debug_info}") end end end @doc """ Asserts that `value` is a valid **response** schema with title `schema_title` in `api_spec`. In this case, the presence of required `writeOnly` fields is not validated. """ @spec assert_response_schema(term, String.t(), OpenApi.t()) :: term | no_return def assert_response_schema(value, schema_title, api_spec = %OpenApi{}) do assert_schema(value, schema_title, api_spec, :read) end @doc """ Asserts that `value` is a valid **request** schema with title `schema_title` in `api_spec`. In this case, the presence of required `readOnly` fields is not validated. """ @spec assert_request_schema(term, String.t(), OpenApi.t()) :: term | no_return def assert_request_schema(value, schema_title, api_spec = %OpenApi{}) do assert_schema(value, schema_title, api_spec, :write) end end