sapor 0.1b1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. checksums.yaml +7 -0
  2. data/Area Class Diagram.dia +0 -0
  3. data/Area Class Diagram.png +0 -0
  4. data/Class Diagram.dia +0 -0
  5. data/Class Diagram.png +0 -0
  6. data/Examples.md +361 -0
  7. data/LICENSE +674 -0
  8. data/README.md +70 -0
  9. data/Rakefile +18 -0
  10. data/Technical Documentation.md +14 -0
  11. data/bin/create_installation_package.sh +49 -0
  12. data/bin/install.sh +45 -0
  13. data/bin/sapor.rb +22 -0
  14. data/bin/sapor.sh +105 -0
  15. data/lib/sapor.rb +44 -0
  16. data/lib/sapor/binomials_cache.rb +45 -0
  17. data/lib/sapor/combinations_distribution.rb +180 -0
  18. data/lib/sapor/dichotomies.rb +98 -0
  19. data/lib/sapor/dichotomy.rb +138 -0
  20. data/lib/sapor/first_past_the_post.rb +78 -0
  21. data/lib/sapor/leveled_proportional.rb +64 -0
  22. data/lib/sapor/log4r_logger.rb +49 -0
  23. data/lib/sapor/log_facade.rb +40 -0
  24. data/lib/sapor/number_formatter.rb +45 -0
  25. data/lib/sapor/poll.rb +137 -0
  26. data/lib/sapor/polychotomy.rb +359 -0
  27. data/lib/sapor/proportional.rb +128 -0
  28. data/lib/sapor/pseudorandom_multirange_enumerator.rb +87 -0
  29. data/lib/sapor/regional_data/area.rb +80 -0
  30. data/lib/sapor/regional_data/catalonia-2012-2015.psv +100 -0
  31. data/lib/sapor/regional_data/catalonia-2012.psv +87 -0
  32. data/lib/sapor/regional_data/catalonia.rb +90 -0
  33. data/lib/sapor/regional_data/norway.rb +408 -0
  34. data/lib/sapor/regional_data/united_kingdom.rb +1075 -0
  35. data/lib/sapor/regional_data/utopia.rb +66 -0
  36. data/sapor.gemspec +35 -0
  37. data/spec/integration/area_spec.rb +28 -0
  38. data/spec/integration/poll_spec.rb +107 -0
  39. data/spec/integration/sample.poll +7 -0
  40. data/spec/spec_helper.rb +31 -0
  41. data/spec/unit/area_spec.rb +115 -0
  42. data/spec/unit/binomials_cache_spec.rb +34 -0
  43. data/spec/unit/catalonia_spec.rb +82 -0
  44. data/spec/unit/combinations_distribution_spec.rb +241 -0
  45. data/spec/unit/denominators_spec.rb +34 -0
  46. data/spec/unit/dichotomies_spec.rb +154 -0
  47. data/spec/unit/dichotomy_spec.rb +320 -0
  48. data/spec/unit/first_past_the_post_spec.rb +53 -0
  49. data/spec/unit/leveled_proportional_spec.rb +51 -0
  50. data/spec/unit/norway_spec.rb +47 -0
  51. data/spec/unit/number_formatter_spec.rb +173 -0
  52. data/spec/unit/poll_spec.rb +105 -0
  53. data/spec/unit/polychotomy_spec.rb +332 -0
  54. data/spec/unit/proportional_spec.rb +86 -0
  55. data/spec/unit/pseudorandom_multirange_enumerator_spec.rb +82 -0
  56. metadata +119 -0
@@ -0,0 +1,66 @@
1
+ # encoding: utf-8
2
+ #
3
+ # Statistical Analysis of Polling Results (SAPoR)
4
+ # Copyright (C) 2014 Filip van Laenen <f.a.vanlaenen@ieee.org>
5
+ #
6
+ # This file is part of SAPoR.
7
+ #
8
+ # SAPoR is free software: you can redistribute it and/or modify it under the
9
+ # terms of the GNU General Public License as published by the Free Software
10
+ # Foundation, either version 3 of the License, or (at your option) any later
11
+ # version.
12
+ #
13
+ # SAPoR is distributed in the hope that it will be useful, but WITHOUT ANY
14
+ # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15
+ # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16
+ #
17
+ # You can find a copy of the GNU General Public License in /doc/gpl.txt
18
+ #
19
+
20
+ module Sapor
21
+ #
22
+ # The regional data for Utopia, an area for testing purposes.
23
+ #
24
+ class Utopia
25
+ include Singleton
26
+
27
+ LAST_ELECTION_RESULT = { 'Red' => 91_811, 'Green' => 190_934,
28
+ 'Blue' => 290_647, 'Yellow' => 356_473 }
29
+
30
+ LAST_DETAILED_ELECTION_RESULT = { 'North' => { 'Red' => 50, 'Green' => 70
31
+ },
32
+ 'South' => { 'Red' => 70, 'Green' => 50,
33
+ 'Blue' => 100 },
34
+ 'East' => { 'Red' => 90, 'Green' => 70,
35
+ 'Blue' => 90 },
36
+ 'West' => { 'Red' => 110, 'Green' => 50,
37
+ 'Yellow' => 120 } }
38
+
39
+ ELECTORAL_SYSTEM = FirstPastThePost.new(LAST_ELECTION_RESULT,
40
+ LAST_DETAILED_ELECTION_RESULT)
41
+
42
+ def area_code
43
+ 'UT'
44
+ end
45
+
46
+ def coalitions
47
+ [['Red', 'Green'], ['Red', 'Blue']]
48
+ end
49
+
50
+ def population_size
51
+ 1_000_000
52
+ end
53
+
54
+ def threshold
55
+ nil
56
+ end
57
+
58
+ def no_of_seats
59
+ LAST_DETAILED_ELECTION_RESULT.size
60
+ end
61
+
62
+ def seats(simulation)
63
+ ELECTORAL_SYSTEM.project(simulation)
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,35 @@
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # Statistical Analysis of Polling Results (SAPoR)
4
+ # Copyright (C) 2014 Filip van Laenen <f.a.vanlaenen@ieee.org>
5
+ #
6
+ # This file is part of SAPoR.
7
+ #
8
+ # SAPoR is free software: you can redistribute it and/or modify it under the
9
+ # terms of the GNU General Public License as published by the Free Software
10
+ # Foundation, either version 3 of the License, or (at your option) any later
11
+ # version.
12
+ #
13
+ # SAPoR is distributed in the hope that it will be useful, but WITHOUT ANY
14
+ # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15
+ # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16
+ #
17
+ # You can find a copy of the GNU General Public License in /doc/gpl.txt
18
+ #
19
+
20
+ Gem::Specification.new do |gem|
21
+ gem.name = 'sapor'
22
+ gem.version = '0.1b1'
23
+ gem.authors = ['Filip van Laenen']
24
+ gem.email = ['f.a.vanlaenen@ieee.org']
25
+
26
+ gem.description = 'SAPoR'
27
+ gem.summary = 'Statistical Analysis of Polling Results'
28
+ gem.homepage = 'https://github.com/filipvanlaenen/sapor'
29
+ gem.license = 'GPL'
30
+
31
+ gem.require_paths = ['lib']
32
+ gem.files = `git ls-files`.split("\n")
33
+ gem.test_files = `git ls-files -- spec`.split("\n")
34
+ gem.extra_rdoc_files = %w(LICENSE README.md)
35
+ end
@@ -0,0 +1,28 @@
1
+ # encoding: utf-8
2
+ #
3
+ # Statistical Analysis of Polling Results (SAPoR)
4
+ # Copyright (C) 2014 Filip van Laenen <f.a.vanlaenen@ieee.org>
5
+ #
6
+ # This file is part of SAPoR.
7
+ #
8
+ # SAPoR is free software: you can redistribute it and/or modify it under the
9
+ # terms of the GNU General Public License as published by the Free Software
10
+ # Foundation, either version 3 of the License, or (at your option) any later
11
+ # version.
12
+ #
13
+ # SAPoR is distributed in the hope that it will be useful, but WITHOUT ANY
14
+ # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15
+ # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16
+ #
17
+ # You can find a copy of the GNU General Public License in /doc/gpl.txt
18
+ #
19
+
20
+ require 'spec_helper'
21
+
22
+ describe Sapor::Area, '#load_election_results' do
23
+ it 'loads four constituencies for the 2012 election results for Catalonia' do
24
+ area = Sapor::Area.instance
25
+ catalonia_2012 = area.load_election_results('catalonia-2012.psv')
26
+ expect(catalonia_2012.size).to eq(4)
27
+ end
28
+ end
@@ -0,0 +1,107 @@
1
+ # encoding: utf-8
2
+ #
3
+ # Statistical Analysis of Polling Results (SAPoR)
4
+ # Copyright (C) 2014 Filip van Laenen <f.a.vanlaenen@ieee.org>
5
+ #
6
+ # This file is part of SAPoR.
7
+ #
8
+ # SAPoR is free software: you can redistribute it and/or modify it under the
9
+ # terms of the GNU General Public License as published by the Free Software
10
+ # Foundation, either version 3 of the License, or (at your option) any later
11
+ # version.
12
+ #
13
+ # SAPoR is distributed in the hope that it will be useful, but WITHOUT ANY
14
+ # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15
+ # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16
+ #
17
+ # You can find a copy of the GNU General Public License in /doc/gpl.txt
18
+ #
19
+
20
+ require 'spec_helper'
21
+
22
+ SAMPLE_FILE = File.join('spec', 'integration', 'sample.poll')
23
+ MAX_ERROR = 0.05
24
+
25
+ #
26
+ # Logger logging messages to an array.
27
+ #
28
+ class ArrayLogger
29
+ attr_reader :messages
30
+
31
+ def initialize
32
+ @messages = []
33
+ end
34
+
35
+ def info(message)
36
+ @messages << message
37
+ end
38
+ end
39
+
40
+ #
41
+ # LoggerBuilder that creates ArrayLogger instances.
42
+ #
43
+ class ArrayLoggerBuilder
44
+ def create_logger
45
+ ArrayLogger.new
46
+ end
47
+ end
48
+
49
+ Sapor::LogFacade.logger_builder = ArrayLoggerBuilder.new
50
+
51
+ describe Sapor::Poll, '#from_file' do
52
+ it 'reads a poll from a file and extracts area' do
53
+ poll = Sapor::Poll.from_file(SAMPLE_FILE)
54
+ expect(poll.area.area_code).to eq('UT')
55
+ end
56
+
57
+ it 'reads a poll from a file and extracts first result' do
58
+ poll = Sapor::Poll.from_file(SAMPLE_FILE)
59
+ expect(poll.result('Red')).to eq(1)
60
+ end
61
+
62
+ it 'reads a poll from a file and extracts last result' do
63
+ poll = Sapor::Poll.from_file(SAMPLE_FILE)
64
+ expect(poll.result('Blue')).to eq(3)
65
+ end
66
+ end
67
+
68
+ describe Sapor::Poll, '#analyze' do
69
+ it 'logs “Analyzing as a set of dichotomies...”' do
70
+ poll = Sapor::Poll.from_file(SAMPLE_FILE)
71
+ poll.analyze(MAX_ERROR)
72
+ expect(poll.logger.messages).to include('Analyzing as a set of' \
73
+ ' dichotomies...')
74
+ end
75
+
76
+ it 'logs “Analyzing as a polychotomy...”' do
77
+ poll = Sapor::Poll.from_file(SAMPLE_FILE)
78
+ poll.analyze(MAX_ERROR)
79
+ expect(poll.logger.messages).to include('Analyzing as a polychotomy...')
80
+ end
81
+
82
+ it 'logs “Done.” at the end' do
83
+ poll = Sapor::Poll.from_file(SAMPLE_FILE)
84
+ poll.analyze(MAX_ERROR)
85
+ expect(poll.logger.messages.last).to eq('Done.')
86
+ end
87
+
88
+ it 'logs error estimates' do
89
+ poll = Sapor::Poll.from_file(SAMPLE_FILE)
90
+ poll.analyze(MAX_ERROR)
91
+ expect(poll.logger.messages).to include('Error estimate: ε ≤ 33.3%.')
92
+ end
93
+
94
+ it 'logs MPV and CI(95%) reports from Dichotomies' do
95
+ poll = Sapor::Poll.from_file(SAMPLE_FILE)
96
+ poll.analyze(MAX_ERROR)
97
+ expected_report = 'Most probable fractions and 95% confidence' \
98
+ " intervals:\n" \
99
+ "Choice MPF CI(95%)\n" \
100
+ "Yellow 46.3% 22.2%– 74.1%\n" \
101
+ "Blue 24.1% 7.4%– 51.9%\n" \
102
+ "Green 16.7% 3.7%– 44.4%\n" \
103
+ "Red 9.3% 0.0%– 37.0%\n" \
104
+ 'Other 9.3% 0.0%– 37.0%'
105
+ expect(poll.logger.messages).to include(expected_report)
106
+ end
107
+ end
@@ -0,0 +1,7 @@
1
+ Area=UT
2
+ ==
3
+ Red=1
4
+ Green=2
5
+ Blue=3
6
+ Yellow=6
7
+ Other=1
@@ -0,0 +1,31 @@
1
+ # encoding: utf-8
2
+ #
3
+ # Statistical Analysis of Polling Results (SAPoR)
4
+ # Copyright (C) 2014 Filip van Laenen <f.a.vanlaenen@ieee.org>
5
+ #
6
+ # This file is part of SAPoR.
7
+ #
8
+ # SAPoR is free software: you can redistribute it and/or modify it under the
9
+ # terms of the GNU General Public License as published by the Free Software
10
+ # Foundation, either version 3 of the License, or (at your option) any later
11
+ # version.
12
+ #
13
+ # SAPoR is distributed in the hope that it will be useful, but WITHOUT ANY
14
+ # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15
+ # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16
+ #
17
+ # You can find a copy of the GNU General Public License in /doc/gpl.txt
18
+ #
19
+
20
+ $LOAD_PATH << 'lib'
21
+ require 'sapor'
22
+
23
+ require 'timeout'
24
+
25
+ RSpec.configure do |config|
26
+ config.around do |example|
27
+ Timeout.timeout(1) do
28
+ example.run
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,115 @@
1
+ # encoding: utf-8
2
+ #
3
+ # Statistical Analysis of Polling Results (SAPoR)
4
+ # Copyright (C) 2014 Filip van Laenen <f.a.vanlaenen@ieee.org>
5
+ #
6
+ # This file is part of SAPoR.
7
+ #
8
+ # SAPoR is free software: you can redistribute it and/or modify it under the
9
+ # terms of the GNU General Public License as published by the Free Software
10
+ # Foundation, either version 3 of the License, or (at your option) any later
11
+ # version.
12
+ #
13
+ # SAPoR is distributed in the hope that it will be useful, but WITHOUT ANY
14
+ # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15
+ # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16
+ #
17
+ # You can find a copy of the GNU General Public License in /doc/gpl.txt
18
+ #
19
+
20
+ require 'spec_helper'
21
+
22
+ NORTH = 'North'
23
+ SOUTH = 'South'
24
+
25
+ RED = 'Red'
26
+ BLUE = 'Blue'
27
+
28
+ NORTH_RED_LINE = "#{NORTH} | #{RED} | 5"
29
+ NORTH_BLUE_LINE = "#{NORTH} | #{BLUE} | 6"
30
+ SOUTH_RED_LINE = "#{SOUTH} | #{RED} | 7"
31
+ SOUTH_BLUE_LINE_WITH_THOUSANDS_SEPARATOR = "#{SOUTH} | #{BLUE} | 8,888,888"
32
+ EMPTY_LINE = ' '
33
+ COMMENT = '# A comment'
34
+ BROKEN_LINE = 'Broken line'
35
+
36
+ describe Sapor::Area, '#lines_to_election_results' do
37
+ it 'converts a single line to 1 constituency' do
38
+ area = Sapor::Area.instance
39
+ election_results = area.lines_to_election_results(NORTH_RED_LINE)
40
+ expect(election_results.size).to eq(1)
41
+ end
42
+
43
+ it 'converts two lines for the same constituency to 1 constituency' do
44
+ area = Sapor::Area.instance
45
+ lines = [NORTH_RED_LINE, NORTH_BLUE_LINE].join("\n")
46
+ election_results = area.lines_to_election_results(lines)
47
+ expect(election_results.size).to eq(1)
48
+ end
49
+
50
+ it 'converts two lines for two constituencies to 2 constituencies' do
51
+ area = Sapor::Area.instance
52
+ lines = [NORTH_RED_LINE, SOUTH_RED_LINE].join("\n")
53
+ election_results = area.lines_to_election_results(lines)
54
+ expect(election_results.size).to eq(2)
55
+ end
56
+
57
+ it 'ignores empty lines' do
58
+ area = Sapor::Area.instance
59
+ lines = [NORTH_RED_LINE, EMPTY_LINE].join("\n")
60
+ election_results = area.lines_to_election_results(lines)
61
+ expect(election_results.size).to eq(1)
62
+ end
63
+
64
+ it 'ignores comments' do
65
+ area = Sapor::Area.instance
66
+ lines = [NORTH_RED_LINE, COMMENT].join("\n")
67
+ election_results = area.lines_to_election_results(lines)
68
+ expect(election_results.size).to eq(1)
69
+ end
70
+
71
+ it 'sets the number of votes for a party in a constituency correctly' do
72
+ area = Sapor::Area.instance
73
+ election_results = area.lines_to_election_results(NORTH_RED_LINE)
74
+ expect(election_results[NORTH][RED]).to eq(5)
75
+ end
76
+
77
+ it 'ignores thousands separators' do
78
+ area = Sapor::Area.instance
79
+ election_results = area.lines_to_election_results(\
80
+ SOUTH_BLUE_LINE_WITH_THOUSANDS_SEPARATOR)
81
+ expect(election_results[SOUTH][BLUE]).to eq(8_888_888)
82
+ end
83
+
84
+ it 'raises an ArgumentError when a line is broken' do
85
+ area = Sapor::Area.instance
86
+ expect { area.lines_to_election_results(BROKEN_LINE) }.to \
87
+ raise_error(ArgumentError, "Broken line: #{BROKEN_LINE}.")
88
+ end
89
+
90
+ it 'raises an ArgumentError if the same choice is added twice to the same ' \
91
+ 'constituency' do
92
+ area = Sapor::Area.instance
93
+ lines = [NORTH_RED_LINE, NORTH_RED_LINE].join("\n")
94
+ expect { area.lines_to_election_results(lines) }.to \
95
+ raise_error(ArgumentError, "Choice #{RED} appeared twice in " \
96
+ "constituency #{NORTH}.")
97
+ end
98
+ end
99
+
100
+ describe Sapor::Area, '#summarize_election_results' do
101
+ it 'summarizes one result to one result' do
102
+ area = Sapor::Area.instance
103
+ election_results = area.lines_to_election_results(NORTH_RED_LINE)
104
+ summary = area.summarize_election_results(election_results)
105
+ expect(summary[RED]).to eq(5)
106
+ end
107
+
108
+ it 'summarizes results of same choice in two constituencies' do
109
+ area = Sapor::Area.instance
110
+ lines = [NORTH_RED_LINE, SOUTH_RED_LINE].join("\n")
111
+ election_results = area.lines_to_election_results(lines)
112
+ summary = area.summarize_election_results(election_results)
113
+ expect(summary[RED]).to eq(12)
114
+ end
115
+ end
@@ -0,0 +1,34 @@
1
+ # encoding: utf-8
2
+ #
3
+ # Statistical Analysis of Polling Results (SAPoR)
4
+ # Copyright (C) 2014 Filip van Laenen <f.a.vanlaenen@ieee.org>
5
+ #
6
+ # This file is part of SAPoR.
7
+ #
8
+ # SAPoR is free software: you can redistribute it and/or modify it under the
9
+ # terms of the GNU General Public License as published by the Free Software
10
+ # Foundation, either version 3 of the License, or (at your option) any later
11
+ # version.
12
+ #
13
+ # SAPoR is distributed in the hope that it will be useful, but WITHOUT ANY
14
+ # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15
+ # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16
+ #
17
+ # You can find a copy of the GNU General Public License in /doc/gpl.txt
18
+ #
19
+
20
+ require 'spec_helper'
21
+
22
+ describe Sapor::BinomialsCache, '#binomial' do
23
+ it 'returns the correct binomial' do
24
+ actual = Sapor::BinomialsCache.binomial(10, 20)
25
+ expected = 10.large_float_binomial_by_product_of_divisions(20)
26
+ expect(actual).to eq(expected)
27
+ end
28
+
29
+ it 'returns the same binomial when asked a second time' do
30
+ first = Sapor::BinomialsCache.binomial(10, 21)
31
+ second = Sapor::BinomialsCache.binomial(10, 21)
32
+ expect(second).to eq(first)
33
+ end
34
+ end
@@ -0,0 +1,82 @@
1
+ # encoding: utf-8
2
+ #
3
+ # Statistical Analysis of Polling Results (SAPoR)
4
+ # Copyright (C) 2014 Filip van Laenen <f.a.vanlaenen@ieee.org>
5
+ #
6
+ # This file is part of SAPoR.
7
+ #
8
+ # SAPoR is free software: you can redistribute it and/or modify it under the
9
+ # terms of the GNU General Public License as published by the Free Software
10
+ # Foundation, either version 3 of the License, or (at your option) any later
11
+ # version.
12
+ #
13
+ # SAPoR is distributed in the hope that it will be useful, but WITHOUT ANY
14
+ # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15
+ # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16
+ #
17
+ # You can find a copy of the GNU General Public License in /doc/gpl.txt
18
+ #
19
+
20
+ require 'spec_helper'
21
+
22
+ describe Sapor::Catalonia, '#area_code' do
23
+ it 'returns ES-CAT as the area code' do
24
+ expect(Sapor::Catalonia.instance.area_code).to eq('ES-CT')
25
+ end
26
+ end
27
+
28
+ describe Sapor::Catalonia, '#coalitions' do
29
+ it 'returns JS and JS+CUP as the coalitions to track' do
30
+ expect(Sapor::Catalonia.instance.coalitions).to include(['Junts pel Sí'])
31
+ expect(Sapor::Catalonia.instance.coalitions).to \
32
+ include(['Junts pel Sí',
33
+ "Candidatura d'Unitat Popular – Alternativa d'Esquerres"])
34
+ end
35
+ end
36
+
37
+ describe Sapor::Catalonia, '#no_of_seats' do
38
+ it 'returns 135 as the number of seats' do
39
+ expect(Sapor::Catalonia.instance.no_of_seats).to eq(135)
40
+ end
41
+ end
42
+
43
+ describe Sapor::Catalonia, '#population_size' do
44
+ it 'returns a population size of 3,668,310' do
45
+ expect(Sapor::Catalonia.instance.population_size).to eq(3_668_310)
46
+ end
47
+ end
48
+
49
+ describe Sapor::Catalonia, '#seats' do
50
+ it 'calculates the number of seats for the election of 2012 (adapted to' \
51
+ ' 2015) correctly' do
52
+ catalonia = Sapor::Catalonia.instance
53
+ results = catalonia.overall_election_results_of_2012_adapted_to_2015
54
+ seats = catalonia.seats(results)
55
+ expect(seats['Junts pel Sí']).to eq(64)
56
+ expect(seats['Partit dels Socialistes de Catalunya']).to eq(20)
57
+ expect(seats['Partit Popular de Catalunya']).to eq(19)
58
+ expect(seats['Catalunya Sí que es Pot']).to eq(13)
59
+ expect(seats['Ciutadans-Partido de la Ciudadanía']).to eq(9)
60
+ expect(seats['Unió Democràtica de Catalunya']).to eq(7)
61
+ expect(seats["Candidatura d'Unitat Popular – Alternativa d'Esquerres"]).to \
62
+ eq(3)
63
+ expect(seats['Plataforma per Catalunya']).to eq(0)
64
+ expect(seats['Solidaritat Catalana per la Independència']).to eq(0)
65
+ expect(seats['Escons en Blanc']).to eq(0)
66
+ expect(seats['Partido Animalista Contra el Maltrato Animal']).to eq(0)
67
+ expect(seats['Pirates de Catalunya']).to eq(0)
68
+ expect(seats['Unió, Progrés i Democràcia']).to eq(0)
69
+ expect(seats['Farts.cat']).to eq(0)
70
+ expect(seats['Via Democràtica']).to eq(0)
71
+ expect(seats["Unificació Comunista d'Espanya"]).to eq(0)
72
+ expect(seats["Partit Republicà d'Esquerra – Izquierda Republicana"]).to \
73
+ eq(0)
74
+ expect(seats['Socialistes i Republicans']).to eq(0)
75
+ end
76
+ end
77
+
78
+ describe Sapor::Catalonia, '#threshold' do
79
+ it 'returns a threshold of 3%' do
80
+ expect(Sapor::Catalonia.instance.threshold).to eq(0.03)
81
+ end
82
+ end