Skip to content

Commit b9a5d45

Browse files
authored
Merge pull request #80 from epochtalk/validate-mutually-exclusive-fixes
Validate mutually exclusive fixes
2 parents 7e71ca6 + 02ec3ed commit b9a5d45

File tree

2 files changed

+75
-18
lines changed

2 files changed

+75
-18
lines changed

lib/epochtalk_server_web/helpers/validate.ex

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,27 +8,10 @@ defmodule EpochtalkServerWeb.Helpers.Validate do
88

99
@doc """
1010
Ensure that `keys` provided in list are mutually exclusive within `attrs` map.
11-
12-
## Example
13-
iex> alias EpochtalkServerWeb.Helpers.Validate
14-
iex> attrs = %{"page" => 1}
15-
iex> Validate.mutually_exclusive!(attrs, ["page", "start"])
16-
:ok
17-
iex> attrs = %{"start" => 1}
18-
iex> Validate.mutually_exclusive!(attrs, ["page", "start"])
19-
:ok
20-
iex> Validate.mutually_exclusive!(attrs, ["start"])
21-
:ok
22-
iex> attrs = %{"page" => 1, "start" => 1}
23-
iex> Validate.mutually_exclusive!(attrs, ["page", "start"])
24-
** (EpochtalkServerWeb.CustomErrors.InvalidPayload) The following payload parameters cannot be passed at the same time: page, start
2511
"""
2612
@spec mutually_exclusive!(attrs :: map, keys :: [String.t()]) :: :ok | no_return
2713
def mutually_exclusive!(attrs, keys) when is_map(attrs) and is_list(keys) do
28-
contains_all_keys =
29-
Enum.reduce(keys, true, fn key, acc -> acc && Map.has_key?(attrs, key) end)
30-
31-
if contains_all_keys && length(keys) > 1,
14+
if map_contains_any_two_keys_in_list?(attrs, keys),
3215
do:
3316
raise(InvalidPayload,
3417
message:
@@ -152,6 +135,29 @@ defmodule EpochtalkServerWeb.Helpers.Validate do
152135
end
153136
end
154137

138+
# entrypoint
139+
defp map_contains_any_two_keys_in_list?(map, list),
140+
do: map_contains_any_two_keys_in_list?(map, list, false)
141+
142+
# if map is empty, return false
143+
defp map_contains_any_two_keys_in_list?(map, _list, _key_found?) when map == %{}, do: false
144+
# if list is empty, return false
145+
defp map_contains_any_two_keys_in_list?(_map, [], _key_found?), do: false
146+
# if key_found? is false
147+
defp map_contains_any_two_keys_in_list?(map, [key | keys] = _list, false = _key_found?) do
148+
# check next key with updated key_found?
149+
map_contains_any_two_keys_in_list?(map, keys, Map.has_key?(map, key))
150+
end
151+
152+
# if key_found? is true
153+
defp map_contains_any_two_keys_in_list?(map, [key | keys] = _list, true = key_found?) do
154+
# if current key is in map, return true
155+
if Map.has_key?(map, key),
156+
do: true,
157+
# otherwise, check next key
158+
else: map_contains_any_two_keys_in_list?(map, keys, key_found?)
159+
end
160+
155161
defp to_bool(str, opts) do
156162
case str do
157163
"true" -> true
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,56 @@
11
defmodule Test.EpochtalkServerWeb.Helpers.Validate do
22
use Test.Support.ConnCase, async: true
33
alias EpochtalkServerWeb.Helpers.Validate
4+
alias EpochtalkServerWeb.CustomErrors.InvalidPayload
45
doctest Validate
6+
7+
describe "mutually_exclusive/2" do
8+
test "given cases, returns correct result" do
9+
cases = [
10+
%{
11+
attrs: %{"page" => 1},
12+
keys: ["page", "start"],
13+
result: :ok
14+
},
15+
%{
16+
attrs: %{"start" => 1},
17+
keys: ["page", "start"],
18+
result: :ok
19+
},
20+
%{
21+
attrs: %{"start" => 1},
22+
keys: ["start"],
23+
result: :ok
24+
},
25+
%{
26+
attrs: %{"page" => 1, "start" => 1},
27+
keys: ["page", "start"],
28+
result: :error
29+
},
30+
%{
31+
attrs: %{"page" => 1, "start" => 1, "stop" => 1},
32+
keys: ["page", "start"],
33+
result: :error
34+
},
35+
%{
36+
attrs: %{"page" => 1, "stop" => 1},
37+
keys: ["page", "start", "stop", "enter"],
38+
result: :error
39+
}
40+
]
41+
42+
cases
43+
|> Enum.each(fn
44+
%{attrs: attrs, keys: keys, result: :error} ->
45+
assert_raise InvalidPayload,
46+
~r/^The following payload parameters cannot be passed at the same time:/,
47+
fn ->
48+
Validate.mutually_exclusive!(attrs, keys)
49+
end
50+
51+
%{attrs: attrs, keys: keys, result: :ok} ->
52+
assert Validate.mutually_exclusive!(attrs, keys) == :ok
53+
end)
54+
end
55+
end
556
end

0 commit comments

Comments
 (0)