Skip to content

Commit 31ac2d7

Browse files
Add property tests and fix bug
1 parent c89a28a commit 31ac2d7

File tree

4 files changed

+71
-60
lines changed

4 files changed

+71
-60
lines changed

lib/pointing_party/vote_calculator.ex

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,7 @@ defmodule PointingParty.VoteCalculator do
1919
end
2020

2121
defp get_points(score_card, users) do
22-
votes =
23-
users
24-
|> Enum.map(fn {_username, %{metas: [%{points: points}]}} ->
25-
points
26-
end)
22+
votes = Enum.map(users, fn {_username, %{metas: [%{points: points}]}} -> points end)
2723

2824
update_score_card(score_card, :votes, votes)
2925
end
@@ -57,9 +53,10 @@ defmodule PointingParty.VoteCalculator do
5753

5854
defp handle_tie(%{majority: nil, calculated_votes: calculated_votes}) do
5955
calculated_votes
60-
|> Enum.sort_by(&elem(&1, 1))
61-
|> Enum.take(2)
56+
|> Enum.sort_by(&elem(&1, 1), &>=/2)
6257
|> Enum.map(&elem(&1, 0))
58+
|> Enum.sort()
59+
|> Enum.take(2)
6360
end
6461

6562
defp handle_tie(%{majority: majority}), do: majority

mix.exs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ defmodule PointingParty.MixProject do
4242
{:jason, "~> 1.0"},
4343
{:plug_cowboy, "~> 2.0"},
4444
{:ex_machina, "~> 2.3", only: :test},
45+
{:mix_test_watch, "~> 0.8", only: :dev, runtime: false},
4546
{:stream_data, "~> 0.1", only: :test}
4647
]
4748
end

mix.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
"gettext": {:hex, :gettext, "0.17.0", "abe21542c831887a2b16f4c94556db9c421ab301aee417b7c4fbde7fbdbe01ec", [:mix], [], "hexpm"},
1212
"jason": {:hex, :jason, "1.1.2", "b03dedea67a99223a2eaf9f1264ce37154564de899fd3d8b9a21b1a6fd64afe7", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"},
1313
"mime": {:hex, :mime, "1.3.1", "30ce04ab3175b6ad0bdce0035cba77bba68b813d523d1aac73d9781b4d193cf8", [:mix], [], "hexpm"},
14+
"mix_test_watch": {:hex, :mix_test_watch, "0.9.0", "c72132a6071261893518fa08e121e911c9358713f62794a90c95db59042af375", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}], "hexpm"},
1415
"phoenix": {:hex, :phoenix, "1.4.9", "746d098e10741c334d88143d3c94cab1756435f94387a63441792e66ec0ee974", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 1.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.8.1 or ~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"},
1516
"phoenix_ecto": {:hex, :phoenix_ecto, "4.0.0", "c43117a136e7399ea04ecaac73f8f23ee0ffe3e07acfcb8062fe5f4c9f0f6531", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.9", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
1617
"phoenix_html": {:hex, :phoenix_html, "2.13.3", "850e292ff6e204257f5f9c4c54a8cb1f6fbc16ed53d360c2b780a3d0ba333867", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},

test/pointing_party/vote_calculator_test.exs

Lines changed: 65 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -2,81 +2,93 @@ defmodule PointingParty.VoteCalculatorTest do
22
use ExUnit.Case, async: true
33
use ExUnitProperties
44

5-
describe "calculate_votes/1" do
6-
setup do
7-
points_map = fixed_map(%{points: integer(1..5)})
5+
alias PointingParty.Card
6+
7+
# Properties
8+
# --------------
9+
# When there is a tie, the result will be a list
10+
# The tie list will be sorted in increasing order
11+
# The tie list will contain unique elements
12+
# The tie list will have exactly two elements
13+
# The tie list contains only integers
14+
# The tie list integers must be valid voting options
15+
# The greatest element in the tie list will not be greater than the highest vote
16+
#
17+
# When there is a winner, the result will be an integer
18+
# When there is a winner, the result will be one of the valid voting options
19+
# When there is a winner, it will not be greater than the highest vote
20+
#
21+
# Notes
22+
# --------------
23+
# Ties can happen when there are even or odd numbers of players
24+
# Winning votes can also have an even or odd number of players
25+
# Single-player games will always have a winner
826

9-
metas_map =
10-
fixed_map(%{
11-
metas: list_of(points_map, length: 1)
12-
})
1327

28+
describe "calculate_votes/1" do
29+
setup do
30+
points_map = fixed_map(%{
31+
points: member_of(Card.points_range())
32+
})
33+
metas_map = fixed_map(%{
34+
metas: list_of(points_map, length: 1)
35+
})
1436
users = nonempty(map_of(string(:alphanumeric), metas_map))
37+
1538
[users: users]
1639
end
1740

18-
property "winning value is a list or a integer", %{users: users} do
19-
check all users <- users do
20-
{_event, winner} = PointingParty.VoteCalculator.calculate_votes(users)
41+
property "calculated vote is a list or an integer", %{users: users} do
42+
check all users <- users,
43+
{_event, winner} = PointingParty.VoteCalculator.calculate_votes(users),
44+
max_runs: 20 do
2145
assert is_list(winner) || is_integer(winner)
2246
end
2347
end
2448

25-
property "tie when winning value is a list, winner when winning value is an integer", %{users: users} do
26-
check all users <- users do
27-
{event, winner} = PointingParty.VoteCalculator.calculate_votes(users)
28-
29-
cond do
30-
is_list(winner) ->
31-
assert event == "tie"
32-
33-
is_integer(winner) ->
34-
assert event == "winner"
35-
end
36-
end
37-
end
38-
39-
property "the winning value is not more than the highest point value", %{users: users} do
40-
check all users <- users do
41-
{_event, winner} = PointingParty.VoteCalculator.calculate_votes(users)
42-
49+
property "the winning value is not more than the highest vote", %{users: users} do
50+
check all users <- users,
51+
max_runs: 20 do
4352
max_vote =
4453
users
4554
|> Enum.map(fn {_username, %{metas: [%{points: points}]}} -> points end)
4655
|> Enum.max()
4756

48-
cond do
49-
is_list(winner) ->
50-
assert Enum.max(winner) <= max_vote
51-
52-
is_integer(winner) ->
53-
assert winner <= max_vote
57+
case PointingParty.VoteCalculator.calculate_votes(users) do
58+
{"winner", winner} -> assert winner <= max_vote
59+
{"tie", [_lesser, greater]} -> assert greater <= max_vote
5460
end
5561
end
5662
end
5763

58-
property "when the winner is a list of two sorted values", %{users: users} do
59-
check all users <- users do
60-
{_event, winner} = PointingParty.VoteCalculator.calculate_votes(users)
61-
62-
if is_list(winner) do
63-
assert length(winner) == 2
64-
65-
votes = Enum.map(users, fn {_username, %{metas: [%{points: points}]}} -> points end)
64+
property "when there is a winner, calculated vote is a valid integer", %{users: users} do
65+
check all users <- users,
66+
{event, winner} = PointingParty.VoteCalculator.calculate_votes(users),
67+
max_runs: 20 do
68+
if event == "winner" do
69+
assert winner in Card.points_range()
70+
end
71+
end
72+
end
6673

67-
calculated_votes =
68-
Enum.reduce(votes, %{}, fn vote, acc ->
69-
value = (acc[vote] || 0) + 1
70-
Map.put(acc, vote, value)
71-
end)
74+
property "when there is a tie, calculated vote is a list with two sorted values", %{users: users} do
75+
check all users <- users,
76+
{event, votes} = PointingParty.VoteCalculator.calculate_votes(users),
77+
max_runs: 20 do
78+
if event == "tie" do
79+
[lesser, greater] = votes
7280

73-
sorted =
74-
calculated_votes
75-
|> Enum.sort_by(fn ({_k, v}) -> v end)
76-
|> Enum.map(fn ({a, _b}) -> a end)
77-
|> Enum.take(2)
81+
assert lesser < greater
82+
end
83+
end
84+
end
7885

79-
assert sorted == winner
86+
property "when there is a tie, calculated vote is a list whose elements are valid integers", %{users: users} do
87+
check all users <- users,
88+
{event, votes} = PointingParty.VoteCalculator.calculate_votes(users),
89+
max_runs: 20 do
90+
if event == "tie" do
91+
assert Enum.all?(votes, fn vote -> vote in Card.points_range() end)
8092
end
8193
end
8294
end

0 commit comments

Comments
 (0)