defmodule Uploadex.Testing do
@moduledoc """
This module simplifies testing and assertions involving `Uploadex`.
## Usage in Tests
The most convenient way to use `Uploadex.Testing` is to `use` the module:
use Uploadex.Testing
That will define all the helper functions you'll need to make assertions.
## Some examples of how to use the functions
```elixir
# Asserting that 2 files were stored
assert_stored_files_count(2)
# Asserting the filenames of the stored files
assert_stored_files(["file1.pdf", "file2.pdf"])
# Asserting the filenames of the stored files ignoring the order
assert_stored_files(["file2.pdf", "file1.pdf"], ignore_order: true)
# Asserting that no file was stored
refute_stored_files()
# Getting all stored files
["file1.pdf", "file2.pdf"] == get_stored_files()
# Asserting that 1 files was deleted
assert_deleted_files_count(1)
# Asserting the filenames of the deleted files
assert_deleted(["file3.pdf", "file4.pdf", "file5.pdf"])
# Asserting the filenames of the deleted files ignoring the order
assert_deleted_files(["file4.pdf", "file5.pdf", "file3.pdf"], ignore_order: true)
# Asserting that no file was deleted
refute_deleted_files()
# Getting all deleted files
["file3.pdf", "file4.pdf", "file5.pdf"] == get_deleted_files()
```
If you need a more low level API, you can directly use the `Uploadex.TestStorage` functions.
"""
import ExUnit.Assertions, only: [assert: 2]
alias Uploadex.TestStorage
@doc """
Imports all functions from `Uploadex.Testing`
and defines a setup callback to start the `Uploadex.TestStorage`.
"""
defmacro __using__(_opts) do
quote do
import Uploadex.Testing
setup :start_test_storage
end
end
@doc """
Starts the `Uploadex.TestStorage`.
After importing it, you can use as a `ExUnit` setup callback:
import Uploadex.Testing
setup :start_test_storage
"""
@spec start_test_storage(context :: map()) :: :ok
def start_test_storage(_ctx \\ %{}) do
TestStorage.start_link()
:ok
end
@doc """
Asserts that the given `expected_count` number of files was stored.
"""
@spec assert_stored_files_count(expected_count :: integer) :: true
def assert_stored_files_count(expected_count) when is_integer(expected_count) do
stored_files = TestStorage.get_stored()
stored_count = Enum.count(stored_files)
error_message = """
Expected #{expected_count} files stored.
Got #{stored_count} instead:
#{inspect(stored_files)}
"""
assert expected_count == stored_count, error_message
end
@doc """
Asserts that the given `expected_count` number of files was deleted.
"""
@spec assert_deleted_files_count(expected_count :: integer) :: true
def assert_deleted_files_count(expected_count) when is_integer(expected_count) do
deleted_files = TestStorage.get_deleted()
deleted_count = Enum.count(deleted_files)
error_message = """
Expected #{expected_count} files deleted.
Got #{deleted_count} instead:
#{inspect(deleted_files)}
"""
assert expected_count == deleted_count, error_message
end
@doc """
Asserts that no file was stored.
"""
@spec refute_stored_files() :: true
def refute_stored_files() do
assert_stored_files_count(0)
end
@doc """
Asserts that no file was deleted.
"""
@spec refute_deleted_files() :: true
def refute_deleted_files() do
assert_deleted_files_count(0)
end
@doc """
Asserts that all the files in `expected_files` were stored
in the exact order that they are passed in the list.
## Options
* `ignoring_order`: if `true`, ignores the order of the files when asserting (defaults to `false`)
"""
@spec assert_stored_files(expected_files :: list(), opts :: [ignoring_order: boolean()]) :: true
def assert_stored_files(expected_files, opts \\ []) do
ignore_order? = opts[:ignoring_order] || false
stored_files = TestStorage.get_stored()
error_message = """
Expected the files
#{inspect(expected_files)}
to be stored. Instead got:
#{inspect(stored_files)}
"""
if ignore_order? do
assert Enum.sort(expected_files) == Enum.sort(stored_files), error_message
else
assert expected_files == stored_files, error_message
end
end
@doc """
Asserts that all the files in `expected_files` were deleted
in the exact order that they are passed in the list.
## Options
* `ignoring_order`: if `true`, ignores the order of the files when asserting (defaults to `false`)
"""
@spec assert_deleted_files(expected_files :: list(), opts :: [ignoring_order: boolean()]) ::
true
def assert_deleted_files(expected_files, opts \\ []) do
ignore_order? = opts[:ignoring_order] || false
deleted_files = TestStorage.get_deleted()
error_message = """
Expected the files
#{inspect(expected_files)}
to be deleted. Instead got:
#{inspect(deleted_files)}
"""
if ignore_order? do
assert Enum.sort(expected_files) == Enum.sort(deleted_files), error_message
else
assert expected_files == deleted_files, error_message
end
end
@doc """
Returns all the stored files.
It's the same as calling `Uploadex.TestStorage.get_stored/0`.
"""
@spec get_stored_files :: list()
defdelegate get_stored_files, to: TestStorage, as: :get_stored
@doc """
Returns all the deleted files.
It's the same as calling `Uploadex.TestStorage.get_deleted/0`.
"""
@spec get_deleted_files :: list()
defdelegate get_deleted_files, to: TestStorage, as: :get_deleted
@doc """
Returns the options used in the `Uploadex.TestStorage`.
It's the same as calling `Uploadex.TestStorage.get_opts/0`.
"""
@spec get_storage_opts :: keyword()
defdelegate get_storage_opts, to: TestStorage, as: :get_opts
end