@@ -2,81 +2,93 @@ defmodule PointingParty.VoteCalculatorTest do
2
2
use ExUnit.Case , async: true
3
3
use ExUnitProperties
4
4
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
8
26
9
- metas_map =
10
- fixed_map ( % {
11
- metas: list_of ( points_map , length: 1 )
12
- } )
13
27
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
+ } )
14
36
users = nonempty ( map_of ( string ( :alphanumeric ) , metas_map ) )
37
+
15
38
[ users: users ]
16
39
end
17
40
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
21
45
assert is_list ( winner ) || is_integer ( winner )
22
46
end
23
47
end
24
48
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
43
52
max_vote =
44
53
users
45
54
|> Enum . map ( fn { _username , % { metas: [ % { points: points } ] } } -> points end )
46
55
|> Enum . max ( )
47
56
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
54
60
end
55
61
end
56
62
end
57
63
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
66
73
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
72
80
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
78
85
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 )
80
92
end
81
93
end
82
94
end
0 commit comments