clear-election-sdk 0.0.1

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.
@@ -0,0 +1,94 @@
1
+ describe ClearElection::Ballot do
2
+
3
+ let(:election) { ClearElection::Factory.election}
4
+
5
+ describe "complete valid ballot" do
6
+
7
+ let(:ballot) { ClearElection::Factory.ballot(election) }
8
+
9
+ it "is valid" do
10
+ ballot.validate(election)
11
+ expect(ballot).to be_valid
12
+ end
13
+ end
14
+
15
+ describe "incomplete ballot" do
16
+
17
+ let(:ballot) { ClearElection::Factory.ballot(election, complete: false) }
18
+
19
+ it "is not fully valid" do
20
+ ballot.validate(election)
21
+ expect(ballot).not_to be_valid
22
+ expect(ballot.errors.first[:message]).to include 'missing contest'
23
+ end
24
+
25
+ it "is valid subject to incompleteness" do
26
+ ballot.validate(election, complete:false)
27
+ expect(ballot).to be_valid
28
+ end
29
+
30
+ end
31
+
32
+ describe "invalid ballot" do
33
+
34
+ def test_invalid_ballot(election, invalid, message)
35
+ ballot = ClearElection::Factory.ballot(election, invalid: invalid)
36
+ ballot.validate(election)
37
+ expect(ballot).not_to be_valid
38
+ expect(ballot.errors.first[:message]).to include message
39
+ end
40
+
41
+ it "validates contestId" do
42
+ test_invalid_ballot election, :contestId, "Invalid contest id"
43
+ end
44
+
45
+ it "validates candidateId" do
46
+ test_invalid_ballot election, :candidateId, "Invalid candidate id"
47
+ end
48
+
49
+ it "validates writeins allowed" do
50
+ election = ClearElection::Factory.election(writeIn: false)
51
+ test_invalid_ballot election, :writeIn, "Write-in not allowed"
52
+ end
53
+
54
+ it "validates unique choices" do
55
+ test_invalid_ballot election, :duplicateChoice, "Duplicate choices"
56
+ end
57
+
58
+ it "validates ranking" do
59
+ test_invalid_ballot election, :ranking, "Invalid ranking"
60
+ end
61
+
62
+ it "validates multiplicity (too few)" do
63
+ test_invalid_ballot election, :multiplicityTooFew, "Invalid multiplicity"
64
+ end
65
+
66
+ it "validates multiplicity (too many)" do
67
+ test_invalid_ballot election, :multiplicityTooMany, "Invalid multiplicity"
68
+ end
69
+ end
70
+
71
+ describe "json" do
72
+
73
+ let(:ballot) { ClearElection::Factory.ballot(election) }
74
+
75
+ it "makes round trip" do
76
+ original_json = JSON.generate ballot.as_json
77
+ final_json = JSON.generate ClearElection::Ballot.from_json(JSON.parse original_json).as_json
78
+ expect(final_json).to eq original_json
79
+ end
80
+ end
81
+
82
+ describe "order" do
83
+ it "is by ballotId" do
84
+ ballots = 4.times.map { ClearElection::Factory.ballot(election) }
85
+ expect(ballots.shuffle.sort.each_cons(2)).to be_all { |a, b| a.ballotId < b.ballotId }
86
+ end
87
+
88
+ it "of contests is by contestId" do
89
+ ballot = ClearElection::Factory.ballot(election)
90
+ expect(ballot.contests.shuffle.sort.each_cons(2)).to be_all { |a, b| a.contestId < b.contestId }
91
+ end
92
+ end
93
+
94
+ end
@@ -0,0 +1,11 @@
1
+ describe ClearElection do
2
+
3
+ it "reads an election" do
4
+ uri = ClearElection::Factory.election_uri
5
+ election = ClearElection::Factory.election
6
+
7
+ stub_request(:get, uri).to_return(body: JSON.generate(election.as_json))
8
+ expect(ClearElection.read(uri).as_json).to eq election.as_json
9
+ end
10
+
11
+ end
@@ -0,0 +1,49 @@
1
+ describe ClearElection::Election do
2
+
3
+ let(:election) { ClearElection::Factory.election }
4
+ let(:pre_open_time) { election.pollsOpen - 1 }
5
+ let(:while_open_time) { election.pollsOpen + (election.pollsClose - election.pollsOpen)/2 }
6
+ let(:post_close_time) { election.pollsClose + 1 }
7
+
8
+ describe "polls_are_now_open?" do
9
+
10
+ it "returns false before polls open" do
11
+ Timecop.travel pre_open_time do
12
+ expect(election.polls_are_now_open?).to be_falsey
13
+ end
14
+ end
15
+
16
+ it "returns true while polls are open" do
17
+ Timecop.travel while_open_time do
18
+ expect(election.polls_are_now_open?).to be_truthy
19
+ end
20
+ end
21
+
22
+ it "returns false after polls close" do
23
+ Timecop.travel post_close_time do
24
+ expect(election.polls_are_now_open?).to be_falsey
25
+ end
26
+ end
27
+ end
28
+
29
+ describe "polls_are_now_closed?" do
30
+
31
+ it "returns false before polls open" do
32
+ Timecop.travel pre_open_time do
33
+ expect(election.polls_are_now_closed?).to be_falsey
34
+ end
35
+ end
36
+
37
+ it "returns false while polls are open" do
38
+ Timecop.travel while_open_time do
39
+ expect(election.polls_are_now_closed?).to be_falsey
40
+ end
41
+ end
42
+
43
+ it "returns false after polls close" do
44
+ Timecop.travel post_close_time do
45
+ expect(election.polls_are_now_closed?).to be_truthy
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,152 @@
1
+ ClearElection::Rspec.setup agent: true
2
+
3
+ #
4
+ # Stub out some rails-specific definitions. These come into play when
5
+ # `:agent` is passed as true to ClearElection::Rspec.setup; which then sets
6
+ # things up so that rspec-rails will use a particular agent URI as the
7
+ # app root.
8
+ #
9
+ module ::Rails
10
+ def self.root
11
+ Pathname.new("spec")
12
+ end
13
+ end
14
+
15
+ $rspec_rails_request_host = "example.com"
16
+
17
+ def host!(hostname)
18
+ $rspec_rails_request_host = hostname
19
+ end
20
+
21
+ module ::ActionDispatch
22
+ class Request
23
+ def initialize(path)
24
+ @path = path
25
+ end
26
+ def base_url
27
+ "http://#{$rspec_rails_request_host}"
28
+ end
29
+ def original_fullpath
30
+ @path
31
+ end
32
+ def original_url
33
+ "Expect me to be overriden"
34
+ end
35
+ end
36
+ end
37
+
38
+
39
+ describe ClearElection::Rspec do
40
+
41
+ describe "stub_election_uri" do
42
+ it "stubs a valid election uri" do
43
+ election = ClearElection::Factory.election
44
+ uri = stub_election_uri(election: election)
45
+ expect(ClearElection.read(uri).as_json).to eq election.as_json
46
+ end
47
+
48
+ it "stubs an invalid election uri" do
49
+ uri = stub_election_uri(valid: false)
50
+ expect(ClearElection.read(uri)).to be_nil
51
+ end
52
+ end
53
+
54
+ describe "stub_election_access_token" do
55
+ let(:election) { ClearElection::Factory.election }
56
+ let(:election_uri) { stub_election_uri(election: election) }
57
+ let(:accessToken) { SecureRandom.hex(10) }
58
+ let(:demographic) { { "group" => "A" } }
59
+
60
+ it "stubs a uri that accepts access token and returns demographic" do
61
+ stub_election_access_token(election_uri: election_uri, accessToken: accessToken, demographic: demographic)
62
+ response = Faraday.post(election.signin.uri + "redeem", { election: election_uri, accessToken: accessToken })
63
+ response_json = JSON.parse response.body
64
+ expect(response_json).to eq "demographic" => demographic
65
+ end
66
+
67
+ it "stubs a uri that rejects access token" do
68
+ stub_election_access_token(election_uri: election_uri, accessToken: accessToken, demographic: demographic, valid: false)
69
+ response = Faraday.post(election.signin.uri + "redeem", { election: election_uri, accessToken: accessToken })
70
+ expect(response.status).to eq 403
71
+ end
72
+ end
73
+
74
+ describe "rails requests" do
75
+ it "hacks request.original_url to be based at my agent url" do
76
+ path = "/relative/path"
77
+ request = ActionDispatch::Request.new(path)
78
+ expect(request.original_url).to eq my_agent_uri + path
79
+ end
80
+ end
81
+
82
+
83
+ describe "api election validation" do
84
+ Response = Struct.new(:status, :body) do
85
+ def has_http_status?(status)
86
+ self.status == status
87
+ end
88
+ end
89
+
90
+ def response
91
+ @response
92
+ end
93
+
94
+ def set_response(status: 200, error: nil)
95
+ body = {}
96
+ body["error"] = error if error
97
+ @response = Response.new(status, JSON.generate(body))
98
+ end
99
+
100
+ describe "verifies election agent" do
101
+ it_behaves_like "api that validates election URI", agent: :booth do
102
+ let(:apicall) { -> uri {
103
+ election = ClearElection.read(uri)
104
+ case
105
+ when election.nil? then set_response status: 422, error: "invalid uri"
106
+ when election.booth.uri != my_agent_uri then set_response status: 422, error: "not booth agent"
107
+ else set_response
108
+ end
109
+ } }
110
+ end
111
+ end
112
+
113
+ describe "verifies election is open" do
114
+ it_behaves_like "api that validates election URI", state: :open do
115
+ let(:apicall) { -> uri {
116
+ election = ClearElection.read(uri)
117
+ case
118
+ when election.nil? then set_response status: 422, error: "invalid uri"
119
+ when !election.polls_are_now_open? then set_response status: 403, error: "polls not open"
120
+ else set_response
121
+ end
122
+ } }
123
+ end
124
+ end
125
+
126
+ describe "verifies election is closed" do
127
+ it_behaves_like "api that validates election URI", state: :closed do
128
+ let(:apicall) { -> uri {
129
+ election = ClearElection.read(uri)
130
+ case
131
+ when election.nil? then set_response status: 422, error: "invalid uri"
132
+ when !election.polls_are_now_closed? then set_response status: 403, error: "polls not closed"
133
+ else set_response
134
+ end
135
+ } }
136
+ end
137
+ end
138
+
139
+ describe "verifies election hasn't opened" do
140
+ it_behaves_like "api that validates election URI", state: :unopen do
141
+ let(:apicall) { -> uri {
142
+ election = ClearElection.read(uri)
143
+ case
144
+ when election.nil? then set_response status: 422, error: "invalid uri"
145
+ when !election.polls_have_not_opened? then set_response status: 403, error: "polls have opened"
146
+ else set_response
147
+ end
148
+ } }
149
+ end
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,9 @@
1
+ describe ClearElection::Schema do
2
+
3
+ describe "api" do
4
+ it "returns booth agent schema with ballot schema expanded in it" do
5
+ schema = ClearElection::Schema.api("booth-agent", version: "0.0")
6
+ expect(schema["definitions"]["ballot"]["title"]).to eq "Ballot"
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,42 @@
1
+ require 'coveralls'
2
+ require 'simplecov'
3
+ require 'simplecov-gem-profile'
4
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
5
+ SimpleCov::Formatter::HTMLFormatter,
6
+ Coveralls::SimpleCov::Formatter
7
+ ]
8
+ SimpleCov.start "gem"
9
+
10
+ require 'timecop'
11
+
12
+ require 'clear-election-sdk'
13
+ require 'clear-election-sdk/rspec'
14
+
15
+ RSpec.configure do |config|
16
+
17
+ # rspec-expectations config goes here. You can use an alternate
18
+ # assertion/expectation library such as wrong or the stdlib/minitest
19
+ # assertions if you prefer.
20
+ config.expect_with :rspec do |expectations|
21
+ # This option will default to `true` in RSpec 4. It makes the `description`
22
+ # and `failure_message` of custom matchers include text for helper methods
23
+ # defined using `chain`, e.g.:
24
+ # be_bigger_than(2).and_smaller_than(4).description
25
+ # # => "be bigger than 2 and smaller than 4"
26
+ # ...rather than:
27
+ # # => "be bigger than 2"
28
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
29
+ end
30
+
31
+ # rspec-mocks config goes here. You can use an alternate test double
32
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
33
+ config.mock_with :rspec do |mocks|
34
+ # Prevents you from mocking or stubbing a method that does not exist on
35
+ # a real object. This is generally recommended, and will default to
36
+ # `true` in RSpec 4.
37
+ mocks.verify_partial_doubles = true
38
+ end
39
+
40
+ config.warnings = true
41
+
42
+ end
metadata ADDED
@@ -0,0 +1,202 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: clear-election-sdk
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - ronen barzel
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-12-22 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: faraday
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: json-schema
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.6'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.6'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: simplecov
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: simplecov-gem-profile
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: webmock
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: timecop
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ description: Ruby SDK for working with ClearElection data. Also includes factory
140
+ and rspec helpers for testing apps
141
+ email:
142
+ - ronen@barzel.org
143
+ executables: []
144
+ extensions: []
145
+ extra_rdoc_files: []
146
+ files:
147
+ - ".gitignore"
148
+ - ".rspec"
149
+ - ".ruby-version"
150
+ - ".travis.yml"
151
+ - Gemfile
152
+ - LICENSE.txt
153
+ - README.md
154
+ - Rakefile
155
+ - clear-election-sdk.gemspec
156
+ - lib/clear-election-sdk.rb
157
+ - lib/clear-election-sdk/ballot.rb
158
+ - lib/clear-election-sdk/election.rb
159
+ - lib/clear-election-sdk/factory.rb
160
+ - lib/clear-election-sdk/rspec.rb
161
+ - lib/clear-election-sdk/schema.rb
162
+ - lib/clear-election-sdk/version.rb
163
+ - schemas/api/booth-agent-0.0.schema.json
164
+ - schemas/ballot-0.0.schema.json
165
+ - schemas/election-0.0.schema.json
166
+ - spec/ballot_spec.rb
167
+ - spec/clear_election_spec.rb
168
+ - spec/election_spec.rb
169
+ - spec/rspec_spec.rb
170
+ - spec/schema_spec.rb
171
+ - spec/spec_helper.rb
172
+ homepage: https://github.com/ClearElection/clear-election-sdk-ruby
173
+ licenses:
174
+ - MIT
175
+ metadata: {}
176
+ post_install_message:
177
+ rdoc_options: []
178
+ require_paths:
179
+ - lib
180
+ required_ruby_version: !ruby/object:Gem::Requirement
181
+ requirements:
182
+ - - ">="
183
+ - !ruby/object:Gem::Version
184
+ version: '0'
185
+ required_rubygems_version: !ruby/object:Gem::Requirement
186
+ requirements:
187
+ - - ">="
188
+ - !ruby/object:Gem::Version
189
+ version: '0'
190
+ requirements: []
191
+ rubyforge_project:
192
+ rubygems_version: 2.2.2
193
+ signing_key:
194
+ specification_version: 4
195
+ summary: Ruby SDK for working with ClearElection data
196
+ test_files:
197
+ - spec/ballot_spec.rb
198
+ - spec/clear_election_spec.rb
199
+ - spec/election_spec.rb
200
+ - spec/rspec_spec.rb
201
+ - spec/schema_spec.rb
202
+ - spec/spec_helper.rb