screenbeacon 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +4 -0
  3. data/.travis.yml +29 -0
  4. data/Gemfile +8 -0
  5. data/LICENSE +21 -0
  6. data/README.rdoc +44 -0
  7. data/Rakefile +7 -0
  8. data/VERSION +1 -0
  9. data/bin/screenbeacon-console +7 -0
  10. data/gemfiles/default-with-activesupport.gemfile +10 -0
  11. data/gemfiles/json.gemfile +12 -0
  12. data/gemfiles/yajl.gemfile +12 -0
  13. data/lib/data/ca-certificates.crt +5165 -0
  14. data/lib/screenbeacon/alert.rb +32 -0
  15. data/lib/screenbeacon/api_operations/create.rb +16 -0
  16. data/lib/screenbeacon/api_operations/delete.rb +11 -0
  17. data/lib/screenbeacon/api_operations/list.rb +17 -0
  18. data/lib/screenbeacon/api_operations/request.rb +42 -0
  19. data/lib/screenbeacon/api_operations/update.rb +17 -0
  20. data/lib/screenbeacon/api_resource.rb +35 -0
  21. data/lib/screenbeacon/errors/api_connection_error.rb +4 -0
  22. data/lib/screenbeacon/errors/api_error.rb +4 -0
  23. data/lib/screenbeacon/errors/authentication_error.rb +4 -0
  24. data/lib/screenbeacon/errors/invalid_request_error.rb +10 -0
  25. data/lib/screenbeacon/errors/screenbeacon_error.rb +20 -0
  26. data/lib/screenbeacon/project.rb +13 -0
  27. data/lib/screenbeacon/screenbeacon_object.rb +263 -0
  28. data/lib/screenbeacon/test.rb +8 -0
  29. data/lib/screenbeacon/util.rb +130 -0
  30. data/lib/screenbeacon/version.rb +3 -0
  31. data/lib/screenbeacon.rb +305 -0
  32. data/screenbeacon.gemspec +27 -0
  33. data/test/screenbeacon/alert_test.rb +14 -0
  34. data/test/screenbeacon/api_resource_test.rb +82 -0
  35. data/test/screenbeacon/project_test.rb +36 -0
  36. data/test/screenbeacon/screenbeacon_object_test.rb +28 -0
  37. data/test/screenbeacon/test_test.rb +36 -0
  38. data/test/screenbeacon/util_test.rb +34 -0
  39. data/test/test_data.rb +147 -0
  40. data/test/test_helper.rb +43 -0
  41. metadata +176 -0
@@ -0,0 +1,305 @@
1
+ # Screenbeacon Ruby bindings
2
+ # API spec at https://screenbeacon.readme.io
3
+ require 'cgi'
4
+ require 'openssl'
5
+ require 'rbconfig'
6
+ require 'set'
7
+ require 'socket'
8
+
9
+ require 'rest-client'
10
+ require 'json'
11
+
12
+ # Version
13
+ require 'screenbeacon/version'
14
+
15
+ # API operations
16
+ require 'screenbeacon/api_operations/create'
17
+ require 'screenbeacon/api_operations/update'
18
+ require 'screenbeacon/api_operations/delete'
19
+ require 'screenbeacon/api_operations/list'
20
+ require 'screenbeacon/api_operations/request'
21
+
22
+ # Resources
23
+ require 'screenbeacon/util'
24
+ require 'screenbeacon/screenbeacon_object'
25
+ require 'screenbeacon/api_resource'
26
+ require 'screenbeacon/project'
27
+ require 'screenbeacon/test'
28
+ require 'screenbeacon/alert'
29
+
30
+ # Errors
31
+ require 'screenbeacon/errors/screenbeacon_error'
32
+ require 'screenbeacon/errors/api_error'
33
+ require 'screenbeacon/errors/api_connection_error'
34
+ require 'screenbeacon/errors/invalid_request_error'
35
+ require 'screenbeacon/errors/authentication_error'
36
+
37
+ module Screenbeacon
38
+ DEFAULT_CA_BUNDLE_PATH = File.dirname(__FILE__) + '/data/ca-certificates.crt'
39
+ @api_base = 'https://api.screenbeacon.com'
40
+
41
+ @ssl_bundle_path = DEFAULT_CA_BUNDLE_PATH
42
+ @verify_ssl_certs = true
43
+
44
+
45
+ class << self
46
+ attr_accessor :api_id, :api_token, :api_base, :verify_ssl_certs, :api_version #, :connect_base, :uploads_base
47
+ end
48
+
49
+ def self.api_url(url='', api_base_url=nil)
50
+ (api_base_url || @api_base) + url
51
+ end
52
+
53
+ def self.request(method, url, api_id, api_token, params={}, headers={}, api_base_url=nil)
54
+ api_base_url = api_base_url || @api_base
55
+
56
+ unless api_id ||= @api_id
57
+ raise AuthenticationError.new('No API ID provided. ' \
58
+ 'Set your API ID using "Screenbeacon.api_id = <API-ID>". ' \
59
+ 'You can generate API ID from the Screenbeacon web interface. ' \
60
+ 'See https://screenbeacon.com/dashboard/settings for details, or email support@screenbeacon.com ' \
61
+ 'if you have any questions.')
62
+ end
63
+
64
+ unless api_token ||= @api_token
65
+ raise AuthenticationError.new('No API token provided. ' \
66
+ 'Set your API token using "Screenbeacon.api_token = <API-TOKEN>". ' \
67
+ 'You can generate API token from the Screenbeacon web interface. ' \
68
+ 'See https://screenbeacon.com/dashboard/settings for details, or email support@screenbeacon.com ' \
69
+ 'if you have any questions.')
70
+ end
71
+
72
+ if api_id =~ /\s/
73
+ raise AuthenticationError.new('Your API key is invalid, as it contains ' \
74
+ 'whitespace. (HINT: You can double-check your API key from the ' \
75
+ 'Screenbeacon web interface. See https://screenbeacon.com/dashboard/settings for details, or ' \
76
+ 'email support@screenbeacon.com if you have any questions.)')
77
+ end
78
+
79
+ if api_token =~ /\s/
80
+ raise AuthenticationError.new('Your API token is invalid, as it contains ' \
81
+ 'whitespace. (HINT: You can double-check your API token from the ' \
82
+ 'Screenbeacon web interface. See https://screenbeacon.com/dashboard/settings for details, or ' \
83
+ 'email support@screenbeacon.com if you have any questions.)')
84
+ end
85
+
86
+ if verify_ssl_certs
87
+ request_opts = {:verify_ssl => OpenSSL::SSL::VERIFY_PEER,
88
+ :ssl_ca_file => @ssl_bundle_path}
89
+ else
90
+ request_opts = {:verify_ssl => false}
91
+ unless @verify_ssl_warned
92
+ @verify_ssl_warned = true
93
+ $stderr.puts("WARNING: Running without SSL cert verification. " \
94
+ "You should never do this in production. " \
95
+ "Execute 'Screenbeacon.verify_ssl_certs = true' to enable verification.")
96
+ end
97
+ end
98
+
99
+ params = Util.objects_to_ids(params)
100
+ url = api_url(url, api_base_url)
101
+
102
+ case method.to_s.downcase.to_sym
103
+ when :get, :head, :delete
104
+ # Make params into GET parameters
105
+ url += "#{URI.parse(url).query ? '&' : '?'}#{uri_encode(params)}" if params && params.any?
106
+ payload = nil
107
+ else
108
+ if headers[:content_type] && headers[:content_type] == "multipart/form-data"
109
+ payload = params
110
+ else
111
+ payload = uri_encode(params)
112
+ end
113
+ end
114
+
115
+ request_opts.update(:headers => request_headers(api_id, api_token).update(headers),
116
+ :method => method, :open_timeout => 30,
117
+ :payload => payload, :url => url, :timeout => 80)
118
+
119
+ begin
120
+ response = execute_request(request_opts)
121
+ rescue SocketError => e
122
+ handle_restclient_error(e, api_base_url)
123
+ rescue NoMethodError => e
124
+ # Work around RestClient bug
125
+ if e.message =~ /\WRequestFailed\W/
126
+ e = APIConnectionError.new('Unexpected HTTP response code')
127
+ handle_restclient_error(e, api_base_url)
128
+ else
129
+ raise
130
+ end
131
+ rescue RestClient::ExceptionWithResponse => e
132
+ if rcode = e.http_code and rbody = e.http_body
133
+ handle_api_error(rcode, rbody)
134
+ else
135
+ handle_restclient_error(e, api_base_url)
136
+ end
137
+ rescue RestClient::Exception, Errno::ECONNREFUSED => e
138
+ handle_restclient_error(e, api_base_url)
139
+ end
140
+
141
+ [parse(response), api_id, api_token]
142
+ end
143
+
144
+ private
145
+
146
+ def self.user_agent
147
+ @uname ||= get_uname
148
+ lang_version = "#{RUBY_VERSION} p#{RUBY_PATCHLEVEL} (#{RUBY_RELEASE_DATE})"
149
+
150
+ {
151
+ :bindings_version => Screenbeacon::VERSION,
152
+ :lang => 'ruby',
153
+ :lang_version => lang_version,
154
+ :platform => RUBY_PLATFORM,
155
+ :engine => defined?(RUBY_ENGINE) ? RUBY_ENGINE : '',
156
+ :publisher => 'screenbeacon',
157
+ :uname => @uname,
158
+ :hostname => Socket.gethostname,
159
+ }
160
+
161
+ end
162
+
163
+ def self.get_uname
164
+ if File.exist?('/proc/version')
165
+ File.read('/proc/version').strip
166
+ else
167
+ case RbConfig::CONFIG['host_os']
168
+ when /linux|darwin|bsd|sunos|solaris|cygwin/i
169
+ _uname_uname
170
+ when /mswin|mingw/i
171
+ _uname_ver
172
+ else
173
+ "unknown platform"
174
+ end
175
+ end
176
+ end
177
+
178
+ def self._uname_uname
179
+ (`uname -a 2>/dev/null` || '').strip
180
+ rescue Errno::ENOMEM # couldn't create subprocess
181
+ "uname lookup failed"
182
+ end
183
+
184
+ def self._uname_ver
185
+ (`ver` || '').strip
186
+ rescue Errno::ENOMEM # couldn't create subprocess
187
+ "uname lookup failed"
188
+ end
189
+
190
+
191
+ def self.uri_encode(params)
192
+ Util.flatten_params(params).
193
+ map { |k,v| "#{k}=#{Util.url_encode(v)}" }.join('&')
194
+ end
195
+
196
+ def self.request_headers(api_id, api_token)
197
+ headers = {
198
+ :user_agent => "Screenbeacon/v1 RubyBindings/#{Screenbeacon::VERSION}",
199
+ # :authorization => "Bearer #{api_id}",
200
+ :content_type => 'application/x-www-form-urlencoded'
201
+ }
202
+
203
+ headers['Screenbeacon-Version'] = api_version if api_version
204
+ headers['X-API-ID'] = api_id
205
+ headers['X-API-TOKEN'] = api_token
206
+
207
+ begin
208
+ headers.update(:x_screenbeacon_client_user_agent => JSON.generate(user_agent))
209
+ rescue => e
210
+ headers.update(:x_screenbeacon_client_raw_user_agent => user_agent.inspect,
211
+ :error => "#{e} (#{e.class})")
212
+ end
213
+ end
214
+
215
+ def self.execute_request(opts)
216
+ RestClient::Request.execute(opts)
217
+ end
218
+
219
+ def self.parse(response)
220
+ begin
221
+ # Would use :symbolize_names => true, but apparently there is
222
+ # some library out there that makes symbolize_names not work.
223
+ response = JSON.parse(response.body)
224
+ rescue JSON::ParserError
225
+ raise general_api_error(response.code, response.body)
226
+ end
227
+
228
+ Util.symbolize_names(response)
229
+ end
230
+
231
+ def self.general_api_error(rcode, rbody)
232
+ APIError.new("Invalid response object from API: #{rbody.inspect} " +
233
+ "(HTTP response code was #{rcode})", rcode, rbody)
234
+ end
235
+
236
+ def self.handle_api_error(rcode, rbody)
237
+ begin
238
+ error_obj = JSON.parse(rbody)
239
+ error_obj = Util.symbolize_names(error_obj)
240
+ error = error_obj[:error] or raise ScreenbeaconError.new # escape from parsing
241
+
242
+ rescue JSON::ParserError, ScreenbeaconError
243
+ raise general_api_error(rcode, rbody)
244
+ end
245
+
246
+ case rcode
247
+ when 400, 404
248
+ raise invalid_request_error error, rcode, rbody, error_obj
249
+ when 401
250
+ raise authentication_error error, rcode, rbody, error_obj
251
+ when 402
252
+ raise card_error error, rcode, rbody, error_obj
253
+ else
254
+ raise api_error error, rcode, rbody, error_obj
255
+ end
256
+
257
+ end
258
+
259
+ def self.invalid_request_error(error, rcode, rbody, error_obj)
260
+ # We're not returning a params as part of the error for now, so set it to nil.
261
+ InvalidRequestError.new(error, nil, rcode, rbody, error_obj)
262
+ end
263
+
264
+ def self.authentication_error(error, rcode, rbody, error_obj)
265
+ AuthenticationError.new(error, rcode, rbody, error_obj)
266
+ end
267
+
268
+ def self.api_error(error, rcode, rbody, error_obj)
269
+ APIError.new(error, rcode, rbody, error_obj)
270
+ end
271
+
272
+ def self.handle_restclient_error(e, api_base_url=nil)
273
+ api_base_url = @api_base unless api_base_url
274
+ connection_message = "Please check your internet connection and try again. " \
275
+ "If this problem persists, you should check Screenbeacon's service status at " \
276
+ "https://twitter.com/screenbeacon, or let us know at support@screenbeacon.com."
277
+
278
+ case e
279
+ when RestClient::RequestTimeout
280
+ message = "Could not connect to Screenbeacon (#{api_base_url}). #{connection_message}"
281
+
282
+ when RestClient::ServerBrokeConnection
283
+ message = "The connection to the server (#{api_base_url}) broke before the " \
284
+ "request completed. #{connection_message}"
285
+
286
+ when RestClient::SSLCertificateNotVerified
287
+ message = "Could not verify Screenbeacon's SSL certificate. " \
288
+ "Please make sure that your network is not intercepting certificates. " \
289
+ "(Try going to https://api.screenbeacon.com in your browser.) " \
290
+ "If this problem persists, let us know at support@screenbeacon.com."
291
+
292
+ when SocketError
293
+ message = "Unexpected error communicating when trying to connect to Screenbeacon. " \
294
+ "You may be seeing this message because your DNS is not working. " \
295
+ "To check, try running 'host screenbeacon.com' from the command line."
296
+
297
+ else
298
+ message = "Unexpected error communicating with Screenbeacon. " \
299
+ "If this problem persists, let us know at support@screenbeacon.com."
300
+
301
+ end
302
+
303
+ raise APIConnectionError.new(message + "\n\n(Network error: #{e.message})")
304
+ end
305
+ end
@@ -0,0 +1,27 @@
1
+ $:.unshift(File.join(File.dirname(__FILE__), 'lib'))
2
+
3
+ require 'screenbeacon/version'
4
+
5
+ spec = Gem::Specification.new do |s|
6
+ s.name = 'screenbeacon'
7
+ s.version = Screenbeacon::VERSION
8
+ s.summary = 'Ruby bindings for the Screenbeacon API'
9
+ s.description = 'Screenbeacon is a visual design testing service.'
10
+ s.authors = ['Jordan Humphreys']
11
+ s.email = ['jordan@screenbeacon.com']
12
+ s.homepage = 'https://screenbeacon.readme.io'
13
+ s.license = 'MIT'
14
+
15
+ s.add_dependency('rest-client', '~> 1.4')
16
+ s.add_dependency('json', '~> 1.8.1')
17
+
18
+ s.add_development_dependency('mocha', '~> 0.13.2')
19
+ s.add_development_dependency('shoulda', '~> 3.4.0')
20
+ s.add_development_dependency('test-unit')
21
+ s.add_development_dependency('rake')
22
+
23
+ s.files = `git ls-files`.split("\n")
24
+ s.test_files = `git ls-files -- test/*`.split("\n")
25
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
26
+ s.require_paths = ['lib']
27
+ end
@@ -0,0 +1,14 @@
1
+ require File.expand_path('../../test_helper', __FILE__)
2
+
3
+ module Screenbeacon
4
+ class AlertTest < ::Test::Unit::TestCase
5
+ should "alerts should be listable" do
6
+ @mock.expects(:get).once.returns(test_response(test_alert_array))
7
+ c = Screenbeacon::Alert.all
8
+ assert c.kind_of? Array
9
+ # TODO: Should be a Screenbeacon::Alert
10
+ assert c[0].kind_of? Screenbeacon::ScreenbeaconObject
11
+ end
12
+
13
+ end
14
+ end
@@ -0,0 +1,82 @@
1
+ # -*- coding: utf-8 -*-
2
+ require File.expand_path('../../test_helper', __FILE__)
3
+
4
+ module Screenbeacon
5
+ class ApiResourceTest < ::Test::Unit::TestCase
6
+ should "creating a new APIResource should not fetch over the network" do
7
+ @mock.expects(:get).never
8
+ Screenbeacon::Project.new("someid")
9
+ end
10
+
11
+ should "creating a new APIResource from a hash should not fetch over the network" do
12
+ @mock.expects(:get).never
13
+ Screenbeacon::Project.construct_from({
14
+ :id => "somecustomer",
15
+ :object => "customer"
16
+ })
17
+ end
18
+
19
+ should "setting an attribute should not cause a network request" do
20
+ @mock.expects(:get).never
21
+ @mock.expects(:post).never
22
+ c = Screenbeacon::Project.new("test_project");
23
+ c.card = {:id => "somecard", :object => "card"}
24
+ end
25
+
26
+ should "accessing id should not issue a fetch" do
27
+ @mock.expects(:get).never
28
+ c = Screenbeacon::Project.new("test_project")
29
+ c.id
30
+ end
31
+
32
+ should "not specifying api credentials should raise an exception" do
33
+ Screenbeacon.api_id = nil
34
+ Screenbeacon.api_token = nil
35
+ assert_raises Screenbeacon::AuthenticationError do
36
+ Screenbeacon::Project.new("test_project").refresh
37
+ end
38
+ end
39
+
40
+ should "using a nil api key should raise an exception" do
41
+ assert_raises TypeError do
42
+ Screenbeacon::Project.all({}, nil)
43
+ end
44
+ assert_raises TypeError do
45
+ Screenbeacon::Project.all({}, { :api_id => nil, :api_token => nil })
46
+ end
47
+ end
48
+
49
+ should "specifying api credentials containing whitespace should raise an exception" do
50
+ Screenbeacon.api_id = "id "
51
+ Screenbeacon.api_token = " token"
52
+ assert_raises Screenbeacon::AuthenticationError do
53
+ Screenbeacon::Project.new("test_project").refresh
54
+ end
55
+ end
56
+
57
+ should "specifying invalid api credentials should raise an exception" do
58
+ Screenbeacon.api_id = "invalid"
59
+ Screenbeacon.api_token = "token"
60
+ response = test_response(test_invalid_api_id_error, 401)
61
+ assert_raises Screenbeacon::AuthenticationError do
62
+ @mock.expects(:get).once.raises(RestClient::ExceptionWithResponse.new(response, 401))
63
+ Screenbeacon::Project.retrieve("failing_project")
64
+ end
65
+ end
66
+
67
+ should "AuthenticationErrors should have an http status, http body, and JSON body" do
68
+ Screenbeacon.api_id = "invalid"
69
+ Screenbeacon.api_token = "token"
70
+ response = test_response(test_invalid_api_id_error, 401)
71
+ begin
72
+ @mock.expects(:get).once.raises(RestClient::ExceptionWithResponse.new(response, 401))
73
+ Screenbeacon::Project.retrieve("failing_project")
74
+ rescue Screenbeacon::AuthenticationError => e
75
+ assert_equal(401, e.http_status)
76
+ assert_equal(true, !!e.http_body)
77
+ assert_equal(true, !!e.json_body[:error])
78
+ assert_equal(test_invalid_api_id_error[:error], e.json_body[:error])
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,36 @@
1
+ require File.expand_path('../../test_helper', __FILE__)
2
+
3
+ module Screenbeacon
4
+ class ProjectTest < ::Test::Unit::TestCase
5
+ should "projects should be listable" do
6
+ @mock.expects(:get).once.returns(test_response(test_project_array))
7
+ c = Screenbeacon::Project.all
8
+ assert c.kind_of? Array
9
+ assert c[0].kind_of? Screenbeacon::ScreenbeaconObject
10
+ end
11
+
12
+ should "project should be deletable" do
13
+ @mock.expects(:delete).once.returns(test_response(test_project({:deleted => true})))
14
+ c = Screenbeacon::Project.new("test_project")
15
+ c.delete
16
+ assert c.deleted
17
+ end
18
+
19
+ # should "projects should be updateable" do
20
+ # @mock.expects(:get).once.returns(test_response(test_project({:name => "fubu"})))
21
+ # @mock.expects(:post).once.returns(test_response(test_project({:name => "barbu"})))
22
+ # c = Screenbeacon::Project.new(test_project({:name => "fubu"})).refresh
23
+ # assert_equal "fubu", c.name
24
+ # c.name = "barbu"
25
+ # c.save
26
+ # assert_equal "barbu", c.name
27
+ # end
28
+
29
+ should "create should return a new project" do
30
+ @mock.expects(:post).once.returns(test_response(test_project))
31
+ c = Screenbeacon::Project.create
32
+ assert_equal "Screenbeacon", c.name
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,28 @@
1
+ require File.expand_path('../../test_helper', __FILE__)
2
+
3
+ module Screenbeacon
4
+ class ScreenbeaconObjectTest < ::Test::Unit::TestCase
5
+ should "implement #respond_to correctly" do
6
+ obj = Screenbeacon::ScreenbeaconObject.construct_from({ :id => 1, :foo => 'bar' })
7
+ assert obj.respond_to?(:id)
8
+ assert obj.respond_to?(:foo)
9
+ assert !obj.respond_to?(:baz)
10
+ end
11
+
12
+ should "marshal a screenbeacon object correctly" do
13
+ obj = Screenbeacon::ScreenbeaconObject.construct_from({ :id => 1, :name => 'Screenbeacon' }, {:api_id => 'apiid', :api_token => 'apitoken'})
14
+ m = Marshal.load(Marshal.dump(obj))
15
+ assert_equal 1, m.id
16
+ assert_equal 'Screenbeacon', m.name
17
+ expected_hash = {:api_id => 'apiid', :api_token => 'apitoken'}
18
+ assert_equal expected_hash, m.instance_variable_get('@opts')
19
+ end
20
+
21
+ should "recursively call to_hash on its values" do
22
+ nested = Screenbeacon::ScreenbeaconObject.construct_from({ :id => 7, :foo => 'bar' })
23
+ obj = Screenbeacon::ScreenbeaconObject.construct_from({ :id => 1, :nested => nested })
24
+ expected_hash = { :id => 1, :nested => { :id => 7, :foo => 'bar' } }
25
+ assert_equal expected_hash, obj.to_hash
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,36 @@
1
+ require File.expand_path('../../test_helper', __FILE__)
2
+
3
+ module Screenbeacon
4
+ class TestTest < ::Test::Unit::TestCase
5
+ should "tests should be listable" do
6
+ @mock.expects(:get).once.returns(test_response(test_test_array))
7
+ c = Screenbeacon::Test.all
8
+ assert c.kind_of? Array
9
+ assert c[0].kind_of? Screenbeacon::ScreenbeaconObject
10
+ end
11
+
12
+ should "test should be deletable" do
13
+ @mock.expects(:delete).once.returns(test_response(test_test({:deleted => true})))
14
+ c = Screenbeacon::Test.new("test_test")
15
+ c.delete
16
+ assert c.deleted
17
+ end
18
+
19
+ # should "tests should be updateable" do
20
+ # @mock.expects(:get).once.returns(test_response(test_test({:name => "fubu"})))
21
+ # @mock.expects(:post).once.returns(test_response(test_test({:name => "barbu"})))
22
+ # c = Screenbeacon::Test.new("test_test").refresh
23
+ # assert_equal "fubu", c.name
24
+ # c.name = "barbu"
25
+ # c.save
26
+ # assert_equal "barbu", c.name
27
+ # end
28
+
29
+ should "create should return a new test" do
30
+ @mock.expects(:post).once.returns(test_response(test_test({:name => "Screenbeacon"})))
31
+ c = Screenbeacon::Test.create
32
+ assert_equal "Screenbeacon", c.name
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,34 @@
1
+ require File.expand_path('../../test_helper', __FILE__)
2
+
3
+ module Screenbeacon
4
+ class UtilTest < ::Test::Unit::TestCase
5
+ should "symbolize_names should convert names to symbols" do
6
+ start = {
7
+ 'foo' => 'bar',
8
+ 'array' => [{ 'foo' => 'bar' }],
9
+ 'nested' => {
10
+ 1 => 2,
11
+ :symbol => 9,
12
+ 'string' => nil
13
+ }
14
+ }
15
+ finish = {
16
+ :foo => 'bar',
17
+ :array => [{ :foo => 'bar' }],
18
+ :nested => {
19
+ 1 => 2,
20
+ :symbol => 9,
21
+ :string => nil
22
+ }
23
+ }
24
+
25
+ symbolized = Screenbeacon::Util.symbolize_names(start)
26
+ assert_equal(finish, symbolized)
27
+ end
28
+
29
+ should "normalize_opts should reject nil keys" do
30
+ assert_raise { Screenbeacon::Util.normalize_opts(nil) }
31
+ assert_raise { Screenbeacon::Util.normalize_opts(:api_id => nil, :api_token => nil) }
32
+ end
33
+ end
34
+ end