wurfl_cloud_client 1.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.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +5 -0
  3. data/Gemfile +4 -0
  4. data/Gemfile.lock +40 -0
  5. data/Rakefile +19 -0
  6. data/lib/wurfl_cloud.rb +49 -0
  7. data/lib/wurfl_cloud/cache/cookie.rb +43 -0
  8. data/lib/wurfl_cloud/cache/local_memory.rb +43 -0
  9. data/lib/wurfl_cloud/cache/memcached.rb +64 -0
  10. data/lib/wurfl_cloud/cache/null.rb +41 -0
  11. data/lib/wurfl_cloud/cache/rails.rb +56 -0
  12. data/lib/wurfl_cloud/client.rb +105 -0
  13. data/lib/wurfl_cloud/configuration.rb +88 -0
  14. data/lib/wurfl_cloud/device_capabilities.rb +78 -0
  15. data/lib/wurfl_cloud/environment.rb +48 -0
  16. data/lib/wurfl_cloud/errors.rb +23 -0
  17. data/lib/wurfl_cloud/helper.rb +21 -0
  18. data/lib/wurfl_cloud/rack/cache_manager.rb +54 -0
  19. data/lib/wurfl_cloud/rails.rb +34 -0
  20. data/lib/wurfl_cloud/version.rb +14 -0
  21. data/spec/files/generic.json +1 -0
  22. data/spec/files/generic_filtered.json +1 -0
  23. data/spec/files/lumia.json +1 -0
  24. data/spec/files/lumia_filtered.json +1 -0
  25. data/spec/files/strange_values.json +1 -0
  26. data/spec/spec_helper.rb +27 -0
  27. data/spec/support/rack_helpers.rb +79 -0
  28. data/spec/support/string_extensions.rb +33 -0
  29. data/spec/wurfl_cloud/client_spec.rb +207 -0
  30. data/spec/wurfl_cloud/configuration_spec.rb +118 -0
  31. data/spec/wurfl_cloud/cookie_cache_spec.rb +51 -0
  32. data/spec/wurfl_cloud/device_capabilities_spec.rb +143 -0
  33. data/spec/wurfl_cloud/environment_spec.rb +93 -0
  34. data/spec/wurfl_cloud/helper_spec.rb +35 -0
  35. data/spec/wurfl_cloud/memcached_cache_spec.rb +122 -0
  36. data/spec/wurfl_cloud/null_cache_spec.rb +37 -0
  37. data/spec/wurfl_cloud/rack_cache_manager_spec.rb +76 -0
  38. data/spec/wurfl_cloud/rails_cache_spec.rb +126 -0
  39. data/spec/wurfl_cloud/server_request_spec.rb +45 -0
  40. data/wurfl_cloud_client.gemspec +38 -0
  41. metadata +171 -0
@@ -0,0 +1,33 @@
1
+ #
2
+ # Copyright (c) 2015 ScientiaMobile Inc.
3
+ #
4
+ # The WURFL Cloud Client is intended to be used in both open-source and
5
+ # commercial environments. To allow its use in as many situations as possible,
6
+ # the WURFL Cloud Client is dual-licensed. You may choose to use the WURFL
7
+ # Cloud Client under either the GNU GENERAL PUBLIC LICENSE, Version 2.0, or
8
+ # the MIT License.
9
+ #
10
+ # Refer to the COPYING.txt file distributed with this package.
11
+ #
12
+ class String
13
+ class << self
14
+ def random(length=20)
15
+ self.generic_random(length, ("0".."z"))
16
+ end
17
+ def az_random(length=20)
18
+ self.generic_random(length, ("a".."z"))
19
+ end
20
+ def aznum_random(length=20)
21
+ self.generic_random(length, ("a".."z").to_a + ("0".."9").to_a)
22
+ end
23
+ def az_random_with_num(length=20, num_lenght=20)
24
+ self.generic_random(length, ("a".."z").to_a)+self.generic_random(length, ("0".."9").to_a)
25
+ end
26
+ def generic_random(length,char_range)
27
+ chars = char_range.to_a
28
+ Array.new.tap do |a|
29
+ 1.upto(length) { |i| a << chars[rand(chars.size-1)]}
30
+ end.join
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,207 @@
1
+ #
2
+ # Copyright (c) 2015 ScientiaMobile Inc.
3
+ #
4
+ # The WURFL Cloud Client is intended to be used in both open-source and
5
+ # commercial environments. To allow its use in as many situations as possible,
6
+ # the WURFL Cloud Client is dual-licensed. You may choose to use the WURFL
7
+ # Cloud Client under either the GNU GENERAL PUBLIC LICENSE, Version 2.0, or
8
+ # the MIT License.
9
+ #
10
+ # Refer to the COPYING.txt file distributed with this package.
11
+ #
12
+ require 'spec_helper'
13
+ require 'wurfl_cloud/cache/local_memory'
14
+
15
+ describe WurflCloud::Client do
16
+ subject { WurflCloud::Client.new(WurflCloud::Environment.new, nil) }
17
+
18
+ it "should contain a device_capabilities object" do
19
+ subject.device_capabilities.should be_instance_of(WurflCloud::DeviceCapabilities)
20
+ end
21
+
22
+ it "should delegate the [] method to the device_capabilities object" do
23
+ capability_name = String.random
24
+ subject.device_capabilities.should_receive(:[]).with(capability_name)
25
+ subject[capability_name]
26
+ end
27
+
28
+ it "should have a read_from_cache method" do
29
+ subject.should respond_to(:read_from_cache)
30
+ end
31
+
32
+ context "the detect_device method" do
33
+ it "should be defined with 2 parameters" do
34
+ WurflCloud::Client.should respond_to(:detect_device).with(2).arguments
35
+ end
36
+
37
+ end
38
+
39
+ context "when using with the default null cache" do
40
+ before(:each) do
41
+ @http_env = {
42
+ "HTTP_USER_AGENT"=>String.random,
43
+ "HTTP_ACCEPT"=>String.random,
44
+ "HTTP_X_WAP_PROFILE"=>String.random,
45
+ "REMOTE_ADDR"=>String.random
46
+ }
47
+ @environment = WurflCloud::Environment.new(@http_env)
48
+ @cache = WurflCloud.configuration.cache(nil)
49
+
50
+ @device_data = File.new("#{File.dirname(__FILE__)}/../files/generic.json").read
51
+
52
+ stub_request(:any, authenticated_uri).to_return(:status=>200, :body => @device_data)
53
+
54
+ @wurfl_client = WurflCloud::Client.detect_device(@environment, @cache)
55
+
56
+ end
57
+
58
+ it "should validate the cache when loading from server" do
59
+ @cache.should_receive(:validate).with(1330016154)
60
+ @wurfl_client.load_from_server!
61
+ end
62
+
63
+ it "should return an instance of the client class" do
64
+ @wurfl_client.should be_instance_of(WurflCloud::Client)
65
+ end
66
+
67
+ it "should call the remote webservice" do
68
+ WebMock.should have_requested(:get, authenticated_uri)
69
+ end
70
+
71
+ it "should call the remote webservice each time detect_device is called" do
72
+ WurflCloud::Client.detect_device(@environment, @cache)
73
+ WebMock.should have_requested(:get, authenticated_uri).times(2)
74
+ end
75
+
76
+
77
+ it "should pass the correct headers" do
78
+ headers = {
79
+ 'User-Agent' => @http_env["HTTP_USER_AGENT"],
80
+ 'X-Cloud-Client' => "WurflCloudClient/Ruby_#{WurflCloud::VERSION}",
81
+ 'X-Forwarded-For' => @http_env["REMOTE_ADDR"],
82
+ 'X-Accept' => @http_env["HTTP_ACCEPT"],
83
+ 'X-Wap-Profile' => @http_env["HTTP_X_WAP_PROFILE"],
84
+ }
85
+ stub_request(:any, authenticated_uri).with(:headers=>headers).to_return(:status=>200, :body => @device_data)
86
+ WurflCloud::Client.detect_device(@environment, @cache)
87
+ end
88
+
89
+ { "is_wireless_device"=>false,
90
+ "browser_id"=>"browser_root",
91
+ "fall_back"=>"root",
92
+ "user_agent"=>"",
93
+ "resolution_width"=>90
94
+ }.each do |key, value|
95
+ it "should return the right values for the capability #{key}" do
96
+ @wurfl_client[key].should ==value
97
+ end
98
+ it "should not call the webservice to read a capability that's present in the answer" do
99
+ value = @wurfl_client[key]
100
+ WebMock.should have_requested(:get, authenticated_uri).times(1)
101
+ end
102
+ end
103
+
104
+ end
105
+
106
+ context "when using with a simple local memory cache" do
107
+
108
+ before(:each) do
109
+ @http_env = {
110
+ "HTTP_USER_AGENT"=>String.random,
111
+ "HTTP_ACCEPT"=>String.random,
112
+ "HTTP_X_WAP_PROFILE"=>String.random,
113
+ "REMOTE_ADDR"=>String.random
114
+ }
115
+ @environment = WurflCloud::Environment.new(@http_env)
116
+ @cache = WurflCloud::Cache::LocalMemory.new
117
+
118
+ @device_data = File.new("#{File.dirname(__FILE__)}/../files/generic.json").read
119
+
120
+ stub_request(:any, authenticated_uri).to_return(:status=>200, :body => @device_data)
121
+ @wurfl_client = WurflCloud::Client.detect_device(@environment, @cache)
122
+ end
123
+
124
+
125
+ it "should call the remote webservice once if the same agent is detected twice" do
126
+ WurflCloud::Client.detect_device(@environment, @cache)
127
+ WebMock.should have_requested(:get, authenticated_uri).times(1)
128
+ end
129
+
130
+ context "requesting a non existent capability" do
131
+ context "just after the capabilities have been read from the server" do
132
+ it "should not call again the webservice" do
133
+ value = @wurfl_client['my_non_existent_capability']
134
+ WebMock.should have_requested(:get, authenticated_uri).times(1)
135
+ end
136
+ it "should return nil" do
137
+ @wurfl_client['my_non_existent_capability'].should be_nil
138
+ end
139
+ end
140
+
141
+ context "detecting the device from the cache" do
142
+ before(:each) do
143
+ @wurfl_client = WurflCloud::Client.detect_device(@environment, @cache)
144
+ end
145
+
146
+ it "should call again the webservice" do
147
+ value = @wurfl_client['my_non_existent_capability']
148
+ WebMock.should have_requested(:get, authenticated_uri).times(2)
149
+ end
150
+
151
+ it "should return nil if it doesn't exist" do
152
+ @wurfl_client['my_non_existent_capability'].should be_nil
153
+ end
154
+
155
+ it "should return the right value if exists" do
156
+ stub_request(:any, authenticated_uri).to_return(:status=>200, :body => %{{"apiVersion":"WurflCloud 1.3.2","mtime":1330016154,"id":"generic","capabilities":{"my_non_existent_capability":"OK"},"errors":{}}})
157
+ @wurfl_client['my_non_existent_capability'].should =="OK"
158
+ end
159
+
160
+ it "should call the webservice only once for each access to the capability value" do
161
+ stub_request(:any, authenticated_uri).to_return(:status=>200, :body => %{{"apiVersion":"WurflCloud 1.3.2","mtime":1330016154,"id":"generic","capabilities":{"my_non_existent_capability":"OK"},"errors":{}}})
162
+ value = @wurfl_client['my_non_existent_capability']
163
+ value = @wurfl_client['my_non_existent_capability']
164
+ WebMock.should have_requested(:get, authenticated_uri).times(2)
165
+ end
166
+ end
167
+ end
168
+ end
169
+
170
+ context "when the webservice has errors" do
171
+ before(:each) do
172
+ @http_env = {
173
+ "HTTP_USER_AGENT"=>String.random,
174
+ "HTTP_ACCEPT"=>String.random,
175
+ "HTTP_X_WAP_PROFILE"=>String.random,
176
+ "REMOTE_ADDR"=>String.random
177
+ }
178
+ @environment = WurflCloud::Environment.new(@http_env)
179
+ @cache = WurflCloud.configuration.cache(nil)
180
+
181
+ @device_data = File.new("#{File.dirname(__FILE__)}/../files/generic.json").read
182
+ end
183
+
184
+ it "should raise WurflCloud::Errors::ConnectionError if there are connection timeouts" do
185
+ stub_request(:any, authenticated_uri).to_timeout
186
+
187
+ expect { WurflCloud::Client.detect_device(@environment, @cache) }.to raise_error(WurflCloud::Errors::ConnectionError)
188
+ end
189
+ it "should raise WurflCloud::Errors::ConnectionError if there are connection errors" do
190
+ stub_request(:any, authenticated_uri).to_raise("some error")
191
+
192
+ expect { WurflCloud::Client.detect_device(@environment, @cache) }.to raise_error(WurflCloud::Errors::ConnectionError)
193
+ end
194
+ it "should raise WurflCloud::Errors::ConnectionError if there are server errors" do
195
+ stub_request(:any, authenticated_uri).to_return(:status=>500)
196
+
197
+ expect { WurflCloud::Client.detect_device(@environment, @cache) }.to raise_error(WurflCloud::Errors::ConnectionError)
198
+ end
199
+ it "should raise WurflCloud::Errors::MalformedResponseError if there are unparsable responses" do
200
+ stub_request(:any, authenticated_uri).to_return(:status=>200, :body => %{badjson})
201
+
202
+ expect { WurflCloud::Client.detect_device(@environment, @cache) }.to raise_error(WurflCloud::Errors::MalformedResponseError)
203
+ end
204
+
205
+ end
206
+
207
+ end
@@ -0,0 +1,118 @@
1
+ #
2
+ # Copyright (c) 2015 ScientiaMobile Inc.
3
+ #
4
+ # The WURFL Cloud Client is intended to be used in both open-source and
5
+ # commercial environments. To allow its use in as many situations as possible,
6
+ # the WURFL Cloud Client is dual-licensed. You may choose to use the WURFL
7
+ # Cloud Client under either the GNU GENERAL PUBLIC LICENSE, Version 2.0, or
8
+ # the MIT License.
9
+ #
10
+ # Refer to the COPYING.txt file distributed with this package.
11
+ #
12
+ require 'spec_helper'
13
+ describe WurflCloud::Configuration do
14
+ after(:all) do
15
+ WurflCloud.configuration = WurflCloud::Configuration.new
16
+ end
17
+
18
+ it "should give a new instance if non defined" do
19
+ WurflCloud.configuration = nil
20
+ WurflCloud.configuration.should be_a(WurflCloud::Configuration)
21
+ end
22
+
23
+ context "the configure method" do
24
+ it "should yield an instance of the configuration" do
25
+ WurflCloud.configure do |config|
26
+ config.should be_a(WurflCloud::Configuration)
27
+ end
28
+ end
29
+
30
+ it "should allow writing of the configuration" do
31
+ str = String.random
32
+ WurflCloud.configure do |config|
33
+ config.host = str
34
+ end
35
+ WurflCloud.configuration.host.should ==str
36
+ end
37
+ end
38
+
39
+ {
40
+ :host => 'api.wurflcloud.com',
41
+ :path => '/v1/json',
42
+ :port => 80,
43
+ :schema => 'http',
44
+ :api_type => 'http',
45
+ :search_parameter => 'search:(%{capabilities})',
46
+ :search_parameter_separator => ',',
47
+ :cache_class => WurflCloud::Cache::Null,
48
+ :cache_options => {}
49
+ }.each do |key, value|
50
+
51
+ it "should have the right default for #{key}" do
52
+ subject.send(key).should ==value
53
+ end
54
+
55
+ it "should allow overriding default of #{key}" do
56
+ v = String.random
57
+ subject.send(:"#{key}=", v)
58
+ subject.send(key).should ==v
59
+ end
60
+
61
+ end
62
+
63
+ it "should return the correct api_uri" do
64
+ c = WurflCloud.configuration
65
+ c.schema = String.random
66
+ c.host = String.random
67
+ c.path = String.random
68
+ c.port = String.random
69
+ c.api_uri.should == "#{c.schema}://#{c.host}:#{c.port}#{c.path}"
70
+ end
71
+
72
+ context "the cache method" do
73
+
74
+ it "should return a @cache_class object " do
75
+ subject.cache(Object.new).should be_a(subject.cache_class)
76
+ end
77
+
78
+ it "should call the initialize method of the cache class " do
79
+ env = Object.new
80
+ subject.cache_class.should_receive(:new).with(subject.cache_options, env)
81
+ cache = subject.cache(env)
82
+ end
83
+
84
+ end
85
+ context "the api_key method" do
86
+
87
+ it "should have the right default" do
88
+ subject.api_key.should =='100000:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
89
+ end
90
+
91
+ it "should allow overriding the default" do
92
+ u = 100000+rand(99999)
93
+ p = String.az_random(32)
94
+ subject.api_key = "#{u}:#{p}"
95
+ subject.api_key.should =="#{u}:#{p}"
96
+ end
97
+
98
+ it "should throw an exception if called with a key with the worng format" do
99
+ expect { subject.api_key = "a wrong api key" }.to raise_error(WurflCloud::Errors::ConfigurationError)
100
+ end
101
+
102
+ it "should have set the api_user value" do
103
+ u = 100000+rand(99999)
104
+ p = String.az_random(32)
105
+ subject.api_key = "#{u}:#{p}"
106
+ subject.api_user.should ==u
107
+ end
108
+
109
+ it "should set the api_password value" do
110
+ u = 100000+rand(99999)
111
+ p = String.az_random(32)
112
+ subject.api_key = "#{u}:#{p}"
113
+ subject.api_password.should ==p
114
+ end
115
+
116
+ end
117
+ end
118
+
@@ -0,0 +1,51 @@
1
+ #
2
+ # Copyright (c) 2015 ScientiaMobile Inc.
3
+ #
4
+ # The WURFL Cloud Client is intended to be used in both open-source and
5
+ # commercial environments. To allow its use in as many situations as possible,
6
+ # the WURFL Cloud Client is dual-licensed. You may choose to use the WURFL
7
+ # Cloud Client under either the GNU GENERAL PUBLIC LICENSE, Version 2.0, or
8
+ # the MIT License.
9
+ #
10
+ # Refer to the COPYING.txt file distributed with this package.
11
+ #
12
+ require 'spec_helper'
13
+ describe WurflCloud::Cache::Cookie do
14
+ subject { WurflCloud::Cache::Cookie.new({}, {}) }
15
+
16
+ context "the object" do
17
+ it { should respond_to(:[]).with(1).argument }
18
+ it { should respond_to(:[]=).with(2).arguments }
19
+ it { should respond_to(:mtime).with(0).arguments }
20
+ it { should respond_to(:mtime=).with(1).argument }
21
+
22
+ it "should not throw errors calling []=" do
23
+ expect { subject[String.random] = String.random }.to_not raise_error
24
+ end
25
+
26
+ it "should store values" do
27
+ key = String.random
28
+ subject[key] = String.random
29
+ subject[key].should_not be_nil
30
+ end
31
+
32
+ end
33
+
34
+ context "for the environment" do
35
+ before(:each) do
36
+ @env = Hash.new
37
+ @cache = WurflCloud::Cache::Cookie.new({}, @env)
38
+ end
39
+
40
+ it "should read the value from the wurfl.cookie.device_cache env variable" do
41
+ @env['wurfl.cookie.device_cache'] = String.random
42
+ @cache[String.random].should ==@env['wurfl.cookie.device_cache']
43
+ end
44
+
45
+ it "should set the value into the wurfl.cookie.device_cache env variable" do
46
+ value = String.random
47
+ @cache[String.random] = value
48
+ @env['wurfl.cookie.device_cache'].should ==value
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,143 @@
1
+ #
2
+ # Copyright (c) 2015 ScientiaMobile Inc.
3
+ #
4
+ # The WURFL Cloud Client is intended to be used in both open-source and
5
+ # commercial environments. To allow its use in as many situations as possible,
6
+ # the WURFL Cloud Client is dual-licensed. You may choose to use the WURFL
7
+ # Cloud Client under either the GNU GENERAL PUBLIC LICENSE, Version 2.0, or
8
+ # the MIT License.
9
+ #
10
+ # Refer to the COPYING.txt file distributed with this package.
11
+ #
12
+ require 'spec_helper'
13
+ describe WurflCloud::DeviceCapabilities do
14
+
15
+ context "the object" do
16
+ it { should respond_to(:[]).with(1).argument }
17
+ it { should respond_to(:[]=).with(2).arguments }
18
+ it { should respond_to(:has_key?).with(1).argument }
19
+ it { should respond_to(:merge).with(1).argument }
20
+ it { should respond_to(:empty?).with(0).arguments }
21
+ it { should respond_to(:mtime).with(0).arguments }
22
+ it { should respond_to(:id).with(0).arguments }
23
+ it { should respond_to(:user_agent).with(0).arguments }
24
+
25
+ it "should store a value by key" do
26
+ key = String.random
27
+ val = String.random
28
+ subject[key] = val
29
+ subject[key].should ==val
30
+ end
31
+
32
+ it "should return true from has_key? if the key is set" do
33
+ key = String.random
34
+ subject[key] = nil
35
+ subject.has_key?(key).should be_true
36
+ end
37
+
38
+ context "when merging" do
39
+ before(:each) do
40
+ subject = WurflCloud::DeviceCapabilities.new
41
+ @old_key = String.random
42
+ @old_val = String.random
43
+ subject[@old_key] = @old_val
44
+
45
+ @new_key = String.random
46
+ @new_val = String.random
47
+ end
48
+
49
+
50
+ context "another DeviceCapabilities object" do
51
+ it "should store a value when merged" do
52
+ subject_2 = WurflCloud::DeviceCapabilities.new
53
+ subject_2[@new_key] = @new_val
54
+ subject.merge(subject_2)
55
+ subject[@new_key].should ==@new_val
56
+ end
57
+
58
+ it "should overwrite a value when merged" do
59
+ subject_2 = WurflCloud::DeviceCapabilities.new
60
+ subject_2[@old_key] = @new_val
61
+ subject.merge(subject_2)
62
+ subject[@old_key].should ==@new_val
63
+ end
64
+ end
65
+
66
+ end
67
+
68
+ context "the empty? method" do
69
+ it "should return true if there are no capabilities defined" do
70
+ WurflCloud::DeviceCapabilities.new.empty?.should be_true
71
+ end
72
+
73
+ it "should return false if there are capabilities defined" do
74
+ subject[String.random] = String.random
75
+ subject.empty?.should be_false
76
+ end
77
+ end
78
+ end
79
+
80
+ context "the parse class method" do
81
+ subject { WurflCloud::DeviceCapabilities }
82
+
83
+ before(:each) do
84
+ @generic_filtered_json = File.new("#{File.dirname(__FILE__)}/../files/generic_filtered.json").read
85
+ end
86
+ it "should exist" do
87
+ WurflCloud::DeviceCapabilities.should respond_to(:parse).with(1).argument
88
+ end
89
+
90
+ it "shuould return a DeviceCapabilities object" do
91
+ WurflCloud::DeviceCapabilities.parse(@generic_filtered_json).should be_a(WurflCloud::DeviceCapabilities)
92
+ end
93
+
94
+ context "the parse result" do
95
+ before(:each) do
96
+ @parsed = WurflCloud::DeviceCapabilities.parse(@generic_filtered_json)
97
+ end
98
+ { "is_wireless_device"=>false,
99
+ "browser_id"=>"browser_root",
100
+ "fall_back"=>"root",
101
+ "user_agent"=>"",
102
+ "device_os_version"=>10.5,
103
+ "resolution_width"=>800
104
+ }.each do |key, value|
105
+ it "should populate the DeviceCapabilities key #{key} with the value #{value.to_s.empty? ? "''" : value} from the json pased in" do
106
+ @parsed[key].should ==value
107
+ end
108
+ end
109
+
110
+ it "should have the mtime set to a Time object" do
111
+ @parsed.mtime.should ==Time.at(1330016154)
112
+ end
113
+
114
+ it "should return the correct wurfl id calling its is method" do
115
+ @parsed.id.should =="generic"
116
+ end
117
+ end
118
+
119
+ context "parsing capabilities with boolean and numeric casted to strings" do
120
+ before(:each) do
121
+ @parsed = WurflCloud::DeviceCapabilities.parse(File.new("#{File.dirname(__FILE__)}/../files/strange_values.json").read)
122
+ end
123
+ { "is_tablet"=>false,
124
+ "is_wireless_device"=>true,
125
+ "resolution_width"=>800,
126
+ "release_date"=>"1994_january"
127
+ }.each do |key, value|
128
+ it "should populate the DeviceCapabilities key #{key} with the correct value #{value.to_s.empty? ? "''" : value} from the json pased in" do
129
+ @parsed[key].should ==value
130
+ end
131
+ end
132
+ end
133
+
134
+ it "should be empty if no capabilities defined in the json" do
135
+ @parsed = WurflCloud::DeviceCapabilities.parse(%{{"apiVersion":"WurflCloud 1.3.2","mtime":1330016154,"id":"generic","capabilities":{},"errors":{}}})
136
+ end
137
+
138
+ it "should raise and error if the json is not in the correct format" do
139
+ expect { WurflCloud::DeviceCapabilities.parse(%{}) }.to raise_error(WurflCloud::Errors::MalformedResponseError)
140
+ end
141
+
142
+ end
143
+ end