@@ -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