Goal: have a personal blog, and try out another point in the 'modular app design with elixir' space. Designing OTP systems with elixir had some interesting ideas.
101 lines
2.3 KiB
Elixir
101 lines
2.3 KiB
Elixir
defmodule Blogex.Test.FakeBlog do
|
|
@moduledoc """
|
|
A test double that implements the same interface as a `use Blogex.Blog`
|
|
module, but backed by an Agent so tests can control the post data.
|
|
|
|
## Usage in tests
|
|
|
|
setup do
|
|
posts = [PostBuilder.build(id: "hello"), PostBuilder.build(id: "world")]
|
|
Blogex.Test.FakeBlog.start(posts, blog_id: :engineering, title: "Eng Blog")
|
|
:ok
|
|
end
|
|
|
|
Then pass `Blogex.Test.FakeBlog` anywhere a blog module is expected.
|
|
"""
|
|
|
|
use Agent
|
|
|
|
@defaults [
|
|
blog_id: :test_blog,
|
|
title: "Test Blog",
|
|
description: "A blog for tests",
|
|
base_path: "/blog/test"
|
|
]
|
|
|
|
def start(posts \\ [], opts \\ []) do
|
|
opts = Keyword.merge(@defaults, opts)
|
|
|
|
state = %{
|
|
posts: posts,
|
|
blog_id: opts[:blog_id],
|
|
title: opts[:title],
|
|
description: opts[:description],
|
|
base_path: opts[:base_path]
|
|
}
|
|
|
|
case Agent.start(fn -> state end, name: __MODULE__) do
|
|
{:ok, pid} -> {:ok, pid}
|
|
{:error, {:already_started, pid}} ->
|
|
Agent.update(__MODULE__, fn _ -> state end)
|
|
{:ok, pid}
|
|
end
|
|
end
|
|
|
|
def stop, do: Agent.stop(__MODULE__)
|
|
|
|
defp get(key), do: Agent.get(__MODULE__, &Map.fetch!(&1, key))
|
|
|
|
def blog_id, do: get(:blog_id)
|
|
def title, do: get(:title)
|
|
def description, do: get(:description)
|
|
def base_path, do: get(:base_path)
|
|
|
|
def all_posts do
|
|
get(:posts)
|
|
|> Enum.filter(& &1.published)
|
|
|> Enum.sort_by(& &1.date, {:desc, Date})
|
|
end
|
|
|
|
def recent_posts(n \\ 5), do: Enum.take(all_posts(), n)
|
|
|
|
def all_tags do
|
|
all_posts()
|
|
|> Enum.flat_map(& &1.tags)
|
|
|> Enum.uniq()
|
|
|> Enum.sort()
|
|
end
|
|
|
|
def posts_by_tag(tag) do
|
|
Enum.filter(all_posts(), fn post -> tag in post.tags end)
|
|
end
|
|
|
|
def get_post!(id) do
|
|
Enum.find(all_posts(), &(&1.id == id)) ||
|
|
raise Blogex.NotFoundError, "post #{inspect(id)} not found"
|
|
end
|
|
|
|
def get_post(id) do
|
|
Enum.find(all_posts(), &(&1.id == id))
|
|
end
|
|
|
|
def paginate(page \\ 1, per_page \\ 10) do
|
|
posts = all_posts()
|
|
total = length(posts)
|
|
total_pages = max(ceil(total / per_page), 1)
|
|
|
|
entries =
|
|
posts
|
|
|> Enum.drop((page - 1) * per_page)
|
|
|> Enum.take(per_page)
|
|
|
|
%{
|
|
entries: entries,
|
|
page: page,
|
|
per_page: per_page,
|
|
total_entries: total,
|
|
total_pages: total_pages
|
|
}
|
|
end
|
|
end
|