Last active
July 27, 2020 12:48
-
-
Save ishikawa/c7c7ec9123bf17b6b7f9cf7256e947f4 to your computer and use it in GitHub Desktop.
submap?/3 for Elixir's map. It's useful for testing API response (see submap_usage_test.exs).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule MapHelpers do | |
@doc """ | |
Checks if `map1`'s entries are all contained in `map2`. | |
## Options | |
- `:recursive` - Recursively checks if a value is map (Default: `false`) | |
## Examples | |
``` | |
iex> submap?(%{}, %{}) | |
true | |
iex> submap?(%{a: 1, b: 2}, %{a: 1, b: 2, c: 3}) | |
true | |
iex> submap?(%{a: 1, b: 2, c: 3}, %{a: 1, b: 2}) | |
false | |
iex> submap?(%{a: 1, b: %{}}, %{a: 1, b: %{c: 1}}) | |
false | |
iex> submap?(%{a: 1, b: %{}}, %{a: 1, b: %{c: 1}}, recursive: true) | |
true | |
``` | |
""" | |
@spec submap?(map, map, [option]) :: boolean when option: {:recursive, boolean} | |
def submap?(map1, map2, opts \\ []) when is_map(map1) and is_map(map2) do | |
recursive = Keyword.get(opts, :recursive, false) | |
map1 | |
|> Enum.all?(fn | |
{k, v} when is_map(v) and recursive -> | |
m = map2[k] | |
is_map(m) && submap?(v, m) | |
{k, v} -> | |
map2[k] === v | |
end) | |
end | |
@doc """ | |
Equivalent to `submap?(map1, map2, recursive: true)`. | |
""" | |
@spec deep_submap?(map, map) :: boolean | |
def deep_submap?(map1, map2), do: submap?(map1, map2, recursive: true) | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule MyApp.SubmapUsageTest do | |
use MyApp.ConnCase | |
import MapHelpers, only: [deep_submap?: 2] | |
test "API response match test", %{conn: conn, user: user} do | |
conn = | |
conn | |
|> get("/users/#{user.id}") | |
# response = %{ | |
# "id": "1772493858641", | |
# "name": "alice", | |
# "profile": %{ | |
# "icon" => "http://avatar.example.com/users/1772493858641", | |
# "description" => "...(long description)" | |
# } | |
# } | |
assert response = json_response(conn, :ok) | |
# Write a helper function that returns an exmaple response, and | |
# we can check the response matches an example with `deep_submap?/2`. | |
assert deep_submap?(user_response(user), response) | |
end | |
defp user_response(user) do | |
# We don't want to check `profile.description`, so omit the field. | |
%{ | |
"id": to_string(user.id), | |
"name": user.name, | |
"profile" => %{ | |
"icon" => "http://avatar.example.com/users/#{user.id}" | |
} | |
} | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment