lita-forecast 0.1.0

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,126 @@
1
+ # -*- coding: UTF-8 -*-
2
+ require 'spec_helper'
3
+
4
+ describe LitaForecast::Mixins do
5
+ include LitaForecast::Mixins
6
+
7
+ describe '#geo_location' do
8
+ let(:geocoder) do
9
+ {
10
+ 'address_components' => [
11
+ { 'long_name' => 'San Francisco', 'types' => %w(locality) },
12
+ { 'short_name' => 'CA', 'types' => %w(administrative_area_level_1) }
13
+ ]
14
+ }
15
+ end
16
+
17
+ context 'when given more than one arg' do
18
+ it 'should raise ArgumentError' do
19
+ expect { geo_location(nil, nil) }.to raise_error ArgumentError
20
+ end
21
+ end
22
+
23
+ context 'when given less than one arg' do
24
+ it 'should raise ArgumentError' do
25
+ expect { geo_location }.to raise_error ArgumentError
26
+ end
27
+ end
28
+
29
+ context 'when result is a Geocoder hash' do
30
+ subject { geo_location(geocoder) }
31
+
32
+ it { should be_an_instance_of Hash }
33
+
34
+ it 'should set the city to "San Francisco"' do
35
+ expect(subject[:city]).to eql 'San Francisco'
36
+ end
37
+
38
+ it 'should set the state to CA' do
39
+ expect(subject[:state]).to eql 'CA'
40
+ end
41
+ end
42
+ end
43
+
44
+ describe '#units' do
45
+ let(:forecast_us) { { 'flags' => { 'units' => 'us' } } }
46
+ let(:forecast_ca) { { 'flags' => { 'units' => 'ca' } } }
47
+
48
+ context 'when given more than one arg' do
49
+ it 'should raise ArgumentError' do
50
+ expect { units(nil, nil) }.to raise_error ArgumentError
51
+ end
52
+ end
53
+
54
+ context 'when given less than one arg' do
55
+ it 'should raise ArgumentError' do
56
+ expect { units }.to raise_error ArgumentError
57
+ end
58
+ end
59
+
60
+ context 'when passed a US ForecastIO response' do
61
+ before do
62
+ @unit = units(forecast_us)
63
+ end
64
+ subject { @unit }
65
+
66
+ it { should be_an_instance_of Hash }
67
+
68
+ context 'when the temp (:t) key' do
69
+ subject { @unit[:t] }
70
+
71
+ it { should be_an_instance_of String }
72
+
73
+ it { should eql 'F' }
74
+ end
75
+
76
+ context 'when the wind (:w) key' do
77
+ subject { @unit[:w] }
78
+
79
+ it { should be_an_instance_of String }
80
+
81
+ it { should eql 'mph' }
82
+ end
83
+
84
+ context 'when the visibility (:v) key' do
85
+ subject { @unit[:v] }
86
+
87
+ it { should be_an_instance_of String }
88
+
89
+ it { should eql 'mi' }
90
+ end
91
+ end
92
+
93
+ context 'when passed a CA ForecastIO response' do
94
+ before do
95
+ @unit = units(forecast_ca)
96
+ end
97
+ subject { @unit }
98
+
99
+ it { should be_an_instance_of Hash }
100
+
101
+ context 'when the temp (:t) key' do
102
+ subject { @unit[:t] }
103
+
104
+ it { should be_an_instance_of String }
105
+
106
+ it { should eql 'C' }
107
+ end
108
+
109
+ context 'when the wind (:w) key' do
110
+ subject { @unit[:w] }
111
+
112
+ it { should be_an_instance_of String }
113
+
114
+ it { should eql 'kmph' }
115
+ end
116
+
117
+ context 'when the visibility (:v) key' do
118
+ subject { @unit[:v] }
119
+
120
+ it { should be_an_instance_of String }
121
+
122
+ it { should eql 'km' }
123
+ end
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,27 @@
1
+ # -*- coding: UTF-8 -*-
2
+ require 'spec_helper'
3
+ require 'redis-namespace'
4
+
5
+ describe LitaForecast do
6
+ describe '::FORECAST_NAMESPACE' do
7
+ subject { LitaForecast::FORECAST_NAMESPACE }
8
+
9
+ it { should be_an_instance_of String }
10
+
11
+ it { should eql 'handlers:forecast' }
12
+ end
13
+
14
+ describe '.redis' do
15
+ it 'should not take any args' do
16
+ expect do
17
+ LitaForecast.redis(nil)
18
+ end.to raise_error ArgumentError
19
+ end
20
+
21
+ context 'under normal conditions' do
22
+ subject { LitaForecast.redis }
23
+
24
+ it { should be_an_instance_of Redis::Namespace }
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,115 @@
1
+ # -*- coding: UTF-8 -*-
2
+ require 'spec_helper'
3
+
4
+ describe LitaForecast::Response do
5
+ let(:forecast) do
6
+ {
7
+ 'currently' => {
8
+ 'temperature' => 100.11,
9
+ 'apparentTemperature' => 102.11,
10
+ 'summary' => 'weather',
11
+ 'windBearing' => 0,
12
+ 'windSpeed' => 5.11,
13
+ 'humidity' => 0.10,
14
+ 'dewPoint' => 20.11,
15
+ 'pressure' => 1020.11,
16
+ 'cloudCover' => 0.01
17
+ },
18
+ 'daily' => {
19
+ 'summary' => 'daily weather',
20
+ 'data' => [
21
+ {
22
+ 'summary' => 'weather today!',
23
+ 'temperatureMax' => 68.0,
24
+ 'temperatureMin' => 60.2,
25
+ 'precipProbability' => 0,
26
+ 'windSpeed' => 0,
27
+ 'windBearing' => 0
28
+ },
29
+ {
30
+ 'summary' => 'weather tomorrow!',
31
+ 'temperatureMax' => 70.0,
32
+ 'temperatureMin' => 62.1,
33
+ 'precipProbability' => 1,
34
+ 'precipType' => 'rain',
35
+ 'windSpeed' => 10,
36
+ 'windBearing' => 270
37
+ }
38
+ ]
39
+ },
40
+ 'minutely' => { 'summary' => 'minutely weather' },
41
+ 'hourly' => { 'summary' => 'hourly weather' },
42
+ 'flags' => { 'units' => 'us' }
43
+ }
44
+ end
45
+ let(:location) { 'San Francisco, CA' }
46
+
47
+ before do
48
+ @response = LitaForecast::Response.new(forecast, location)
49
+ end
50
+
51
+ describe '.new' do
52
+ context 'when given more than two args' do
53
+ it 'should raise ArgumentError' do
54
+ expect do
55
+ LitaForecast::Response.new(nil, nil, nil)
56
+ end.to raise_error ArgumentError
57
+ end
58
+ end
59
+
60
+ context 'when given less than two args' do
61
+ it 'should raise ArgumentError' do
62
+ expect do
63
+ LitaForecast::Response.new(nil)
64
+ end.to raise_error ArgumentError
65
+ end
66
+ end
67
+
68
+ context 'when given forecast and location' do
69
+ subject { LitaForecast::Response.new(forecast, location) }
70
+
71
+ it { should be_an_instance_of LitaForecast::Response }
72
+
73
+ it 'should set the @forecast instance variable' do
74
+ i = subject.instance_variable_get(:@forecast)
75
+ expect(i).to eql forecast
76
+ end
77
+
78
+ it 'should set the @location instance variable' do
79
+ i = subject.instance_variable_get(:@location)
80
+ expect(i).to eql location
81
+ end
82
+ end
83
+ end
84
+
85
+ describe '.generate' do
86
+ let(:fc_s) do
87
+ 'Now: 100.1F (feels like 102.1F) weather; Winds N 5.1mph; Humidity 10%' \
88
+ "; Dew Pt 20.1F; Pressure 1020.1mb; Cloud cover 1%.\n" \
89
+ 'Next hour: minutely weather Next 24h: hourly weather'
90
+ end
91
+ let(:ff_s) do
92
+ "Summary: daily weather\n" \
93
+ "Today: weather today! High 68F, Low 60F. 0% chance of " \
94
+ "precipitation. Winds N 0mph.\n" \
95
+ "Tomorrow: weather tomorrow! High 70F, Low 62F. 100% chance of " \
96
+ "rain. Winds W 10mph.\n"
97
+ end
98
+
99
+ context 'given more than one arg' do
100
+ it 'should raise ArgumentError' do
101
+ expect do
102
+ @response.generate(nil)
103
+ end.to raise_error ArgumentError
104
+ end
105
+ end
106
+
107
+ context 'when called' do
108
+ subject { @response.generate }
109
+
110
+ it { should be_an_instance_of String }
111
+
112
+ it { should eql "San Francisco, CA:\n\n#{fc_s}\n\n#{ff_s}" }
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,147 @@
1
+ # -*- coding: UTF-8 -*-
2
+ require 'spec_helper'
3
+
4
+ # Class for stubbing Redis class
5
+ #
6
+ class MockRedisClass
7
+ def self.hgetall(search)
8
+ Hashie::Mash.new({})
9
+ end
10
+ end
11
+
12
+ # Class for mocking LitaResponse object
13
+ #
14
+ class MockResponseClass
15
+ def self.args
16
+ []
17
+ end
18
+ end
19
+
20
+ describe LitaForecast::Weather do
21
+ include LitaForecast::Weather
22
+ let(:forecast_h) do
23
+ {
24
+ 'currently' => {
25
+ 'temperature' => 100.11,
26
+ 'apparentTemperature' => 102.11,
27
+ 'summary' => 'weather',
28
+ 'windBearing' => 0,
29
+ 'windSpeed' => 5.11,
30
+ 'humidity' => 0.10,
31
+ 'dewPoint' => 20.11,
32
+ 'pressure' => 1020.11,
33
+ 'cloudCover' => 0.01
34
+ },
35
+ 'daily' => {
36
+ 'summary' => 'daily weather',
37
+ 'data' => [
38
+ {
39
+ 'summary' => 'weather today!',
40
+ 'temperatureMax' => 68.0,
41
+ 'temperatureMin' => 60.2,
42
+ 'precipProbability' => 0,
43
+ 'windSpeed' => 0,
44
+ 'windBearing' => 0
45
+ },
46
+ {
47
+ 'summary' => 'weather tomorrow!',
48
+ 'temperatureMax' => 70.0,
49
+ 'temperatureMin' => 62.1,
50
+ 'precipProbability' => 1,
51
+ 'precipType' => 'rain',
52
+ 'windSpeed' => 10,
53
+ 'windBearing' => 270
54
+ }
55
+ ]
56
+ },
57
+ 'minutely' => { 'summary' => 'minutely weather' },
58
+ 'hourly' => { 'summary' => 'hourly weather' },
59
+ 'flags' => { 'units' => 'us' }
60
+ }
61
+ end
62
+ let(:good_string) do
63
+ "San Francisco, CA:\n\nNow: 100.1F (feels like 102.1F) weather; Winds " \
64
+ "N 5.1mph; Humidity 10%; Dew Pt 20.1F; Pressure 1020.1mb; Cloud cover " \
65
+ "1%.\nNext hour: minutely weather Next 24h: hourly weather\n\nSummary: " \
66
+ "daily weather\nToday: weather today! High 68F, Low 60F. 0% chance of " \
67
+ "precipitation. Winds N 0mph.\nTomorrow: weather tomorrow! High 70F, " \
68
+ "Low 62F. 100% chance of rain. Winds W 10mph.\n"
69
+ end
70
+
71
+ describe '#weather_forecast' do
72
+ context 'when given more than three args' do
73
+ it 'should raise ArgumentError' do
74
+ expect do
75
+ weather_forecast(nil, nil, nil)
76
+ end.to raise_error ArgumentError
77
+ end
78
+ end
79
+
80
+ context 'when given less than one arg' do
81
+ it 'should raise ArgumentError' do
82
+ expect do
83
+ weather_forecast
84
+ end.to raise_error ArgumentError
85
+ end
86
+ end
87
+
88
+ context 'when passed an API key and location hash' do
89
+ before do
90
+ allow(ForecastIO).to receive(:api_key=)
91
+ .with(any_args).and_return(nil)
92
+ allow(ForecastIO).to receive(:forecast)
93
+ .with(any_args).and_return(forecast_h)
94
+ end
95
+
96
+ let(:l_h) do
97
+ {
98
+ params: {},
99
+ lat: 37.7749295,
100
+ lng: -122.4194155
101
+ }
102
+ end
103
+ subject { weather_forecast('', l_h) }
104
+
105
+ it { should be_an_instance_of Hash }
106
+
107
+ it { should eql forecast_h }
108
+ end
109
+ end
110
+
111
+ describe '#weather' do
112
+ context 'when given more than three args' do
113
+ it 'should raise ArgumentError' do
114
+ expect do
115
+ weather(nil, nil, nil, nil)
116
+ end.to raise_error ArgumentError
117
+ end
118
+ end
119
+
120
+ context 'when given less than two args' do
121
+ it 'should raise ArgumentError' do
122
+ expect do
123
+ weather(nil)
124
+ end.to raise_error ArgumentError
125
+ end
126
+ end
127
+
128
+ context 'when given response and api_key' do
129
+ before do
130
+ allow(LitaForecast).to receive(:redis).and_return(MockRedisClass)
131
+ allow(self).to receive(:weather_forecast)
132
+ .and_return(forecast_h)
133
+ allow_any_instance_of(LitaForecast::Location)
134
+ .to receive(:find_location).with(any_args)
135
+ .and_return(
136
+ lat: 37.7749295, lng: -122.4194155, desc: 'San Francisco, CA'
137
+ )
138
+ end
139
+
140
+ subject { weather(MockResponseClass, '') }
141
+
142
+ it { should be_an_instance_of String }
143
+
144
+ it { should eql good_string }
145
+ end
146
+ end
147
+ end
@@ -0,0 +1,296 @@
1
+ # -*- coding: UTF-8 -*-
2
+ require 'spec_helper'
3
+
4
+ describe Lita::Handlers::ForecastLocations, lita_handler: true do
5
+
6
+ it { routes_command('wadd place 42 42').to(:location_add) }
7
+
8
+ it { routes_command('wadd place 42 42 theplace').to(:location_add) }
9
+
10
+ it { routes_command('wrm place').to(:location_rm) }
11
+
12
+ it { routes_command('wl').to(:locations) }
13
+
14
+ describe '.saved_location_hash' do
15
+ context 'when given a description' do
16
+ let(:location) { ['home', '42', '42', 'my place'] }
17
+
18
+ it 'should return a location hash with unique description' do
19
+ l = { name: 'home', lat: '42', lng: '42', desc: 'my place' }
20
+
21
+ expect(subject.send(:saved_location_hash, location)).to eql l
22
+ end
23
+ end
24
+
25
+ context 'when not given a description' do
26
+ let(:location) { %w(home 42 42) }
27
+
28
+ it 'should return a location hash with the alias as the desc.' do
29
+ l = { name: 'home', lat: '42', lng: '42', desc: 'home' }
30
+
31
+ expect(subject.send(:saved_location_hash, location)).to eql l
32
+ end
33
+ end
34
+ end
35
+
36
+ describe '.rm_from_cache' do
37
+ context 'when passed more than one arg' do
38
+ it 'should raise ArgumentError' do
39
+ expect do
40
+ subject.send(:rm_from_cache, nil, nil)
41
+ end.to raise_error ArgumentError
42
+ end
43
+ end
44
+
45
+ context 'when passed less than one arg' do
46
+ it 'should raise ArgumentError' do
47
+ expect do
48
+ subject.send(:rm_from_cache)
49
+ end.to raise_error ArgumentError
50
+ end
51
+ end
52
+
53
+ context 'when passed a key, "alias:sf"' do
54
+ before do
55
+ allow(LitaForecast.redis).to receive(:del).and_return(nil)
56
+ end
57
+ it 'should call LitaForecast.redis.del to delete the key' do
58
+ key = 'alias:sf'
59
+ expect(LitaForecast.redis).to receive(:del).with(key).once
60
+ expect(subject.send(:rm_from_cache, key)).to be_nil
61
+ end
62
+ end
63
+ end
64
+
65
+ describe '.add_to_cache' do
66
+ context 'when passed more than one arg' do
67
+ it 'should raise ArgumentError' do
68
+ expect do
69
+ subject.send(:add_to_cache, nil, nil)
70
+ end.to raise_error ArgumentError
71
+ end
72
+ end
73
+
74
+ context 'when passed less than one arg' do
75
+ it 'should raise ArgumentError' do
76
+ expect do
77
+ subject.send(:add_to_cache)
78
+ end.to raise_error ArgumentError
79
+ end
80
+ end
81
+
82
+ context 'when passed a location' do
83
+ before do
84
+ @l_h = { name: 'sf', desc: 'sf', lat: 37.7830503, lng: -122.3933962 }
85
+ allow(LitaForecast.redis).to receive(:hset).and_return(nil)
86
+ allow(LitaForecast.redis).to receive(:pipelined).and_yield
87
+ end
88
+
89
+ it 'should add the keys to the cache' do
90
+ expect(LitaForecast.redis).to receive(:hset)
91
+ .with('alias:sf', 'lat', 37.7830503).once
92
+ expect(LitaForecast.redis).to receive(:hset)
93
+ .with('alias:sf', 'lng', -122.3933962).once
94
+ expect(LitaForecast.redis).to receive(:hset)
95
+ .with('alias:sf', 'desc', 'sf').once
96
+ subject.send(:add_to_cache, @l_h)
97
+ end
98
+ end
99
+ end
100
+
101
+ describe '.already_exists?' do
102
+ context 'when given more than one arg' do
103
+ it 'should raise ArgumentError' do
104
+ expect do
105
+ subject.send(:alias_exists?, nil, nil)
106
+ end.to raise_error ArgumentError
107
+ end
108
+ end
109
+
110
+ context 'when given less than one arg' do
111
+ it 'should raise ArgumentError' do
112
+ expect do
113
+ subject.send(:alias_exists?)
114
+ end.to raise_error ArgumentError
115
+ end
116
+ end
117
+
118
+ context 'when key exists' do
119
+ before do
120
+ @h = { desc: 'sf', lat: 37.7830503, lng: -122.3933962 }
121
+ @key = 'alias:sf'
122
+ allow(LitaForecast.redis).to receive(:hgetall).with(@key)
123
+ .and_return(@h)
124
+ end
125
+
126
+ it 'should return true' do
127
+ expect(subject.send(:alias_exists?, @key)).to be_truthy
128
+ end
129
+ end
130
+
131
+ context 'when key does not exist' do
132
+ before do
133
+ @key = 'alias:toronto' # sorry Canadia
134
+ allow(LitaForecast.redis).to receive(:hgetall).with(@key)
135
+ .and_return({})
136
+ end
137
+
138
+ it 'should return true' do
139
+ expect(subject.send(:alias_exists?, @key)).to be_falsey
140
+ end
141
+ end
142
+ end
143
+
144
+ describe '.locations' do
145
+ context 'when given more than one arg' do
146
+ it 'should raise ArgumentError' do
147
+ expect do
148
+ subject.locations(nil, nil)
149
+ end.to raise_error ArgumentError
150
+ end
151
+ end
152
+
153
+ context 'when given more than one arg' do
154
+ it 'should raise ArgumentError' do
155
+ expect do
156
+ subject.locations
157
+ end.to raise_error ArgumentError
158
+ end
159
+ end
160
+
161
+ context 'when aliases exist' do
162
+ before do
163
+ allow(LitaForecast.redis).to receive(:keys).with('alias:*')
164
+ .and_return(%w(alias:sf alias:toronto))
165
+ end
166
+
167
+ it 'should return a list of aliases' do
168
+ send_command('wl')
169
+ expect(replies.last).to eql 'Known weather aliases: sf, toronto'
170
+ end
171
+ end
172
+
173
+ context 'when aliases exist' do
174
+ before do
175
+ allow(LitaForecast.redis).to receive(:keys).with('alias:*')
176
+ .and_return([])
177
+ end
178
+
179
+ it 'should return a list of aliases' do
180
+ send_command('wl')
181
+ expect(replies.last).to eql 'There are no weather aliases'
182
+ end
183
+ end
184
+ end
185
+
186
+ describe '.location_rm' do
187
+ context 'when given more than one arg' do
188
+ it 'should raise ArgumentError' do
189
+ expect do
190
+ subject.location_rm(nil, nil)
191
+ end.to raise_error ArgumentError
192
+ end
193
+ end
194
+
195
+ context 'when given less than one arg' do
196
+ it 'should raise ArgumentError' do
197
+ expect do
198
+ subject.location_rm
199
+ end
200
+ end
201
+ end
202
+
203
+ context 'when the alias does not exist' do
204
+ before do
205
+ allow_any_instance_of(Lita::Handlers::ForecastLocations)
206
+ .to receive(:alias_exists?).with('alias:sf').and_return(false)
207
+ end
208
+
209
+ it 'should return that there was no alias' do
210
+ send_command('wrm sf')
211
+ expect(replies.last).to eql 'Alias not found'
212
+ end
213
+ end
214
+
215
+ context 'when the alias exists and is removed' do
216
+ before do
217
+ key = 'alias:sf'
218
+ allow_any_instance_of(Lita::Handlers::ForecastLocations)
219
+ .to receive(:alias_exists?).with(key).and_return(true)
220
+ allow_any_instance_of(Lita::Handlers::ForecastLocations)
221
+ .to receive(:rm_from_cache).with(key).and_return(nil)
222
+ allow(LitaForecast.redis).to receive(:keys).with(key)
223
+ .and_return([])
224
+ end
225
+
226
+ it 'should return that there was no alias' do
227
+ send_command('wrm sf')
228
+ expect(replies.last).to eql 'Alias removed!'
229
+ end
230
+ end
231
+
232
+ context 'when the alias exists and fails to remove' do
233
+ before do
234
+ key = 'alias:sf'
235
+ allow_any_instance_of(Lita::Handlers::ForecastLocations)
236
+ .to receive(:alias_exists?).with(key).and_return(true)
237
+ allow_any_instance_of(Lita::Handlers::ForecastLocations)
238
+ .to receive(:rm_from_cache).with(key).and_return(nil)
239
+ allow(LitaForecast.redis).to receive(:keys).with(key)
240
+ .and_return(['alias:sf'])
241
+ end
242
+
243
+ it 'should return that there was no alias' do
244
+ send_command('wrm sf')
245
+ expect(replies.last).to eql 'Somehow that failed... I need an adult!'
246
+ end
247
+ end
248
+ end
249
+
250
+ describe '.location_add' do
251
+ context 'when given more than one arg' do
252
+ it 'should raise ArgumentError' do
253
+ expect do
254
+ subject.location_add(nil, nil)
255
+ end.to raise_error ArgumentError
256
+ end
257
+ end
258
+
259
+ context 'when given less than one arg' do
260
+ it 'should raise ArgumentError' do
261
+ expect do
262
+ subject.location_add
263
+ end.to raise_error ArgumentError
264
+ end
265
+ end
266
+
267
+ context 'when the alias already exists' do
268
+ before do
269
+ allow_any_instance_of(Lita::Handlers::ForecastLocations)
270
+ .to receive(:alias_exists?).and_return(true)
271
+ end
272
+
273
+ it 'should return "Already there!"' do
274
+ send_command('wadd sf 37.7830503 -122.3933962')
275
+ expect(replies.last).to eql 'Already there!'
276
+ end
277
+ end
278
+
279
+ context 'when alias does not exist' do
280
+ before do
281
+ allow_any_instance_of(Lita::Handlers::ForecastLocations)
282
+ .to receive(:alias_exists?).and_return(false)
283
+ allow_any_instance_of(Lita::Handlers::ForecastLocations)
284
+ .to receive(:saved_location_hash).and_return(nil)
285
+ allow_any_instance_of(Lita::Handlers::ForecastLocations)
286
+ .to receive(:add_to_cache).and_return(nil)
287
+ end
288
+
289
+ it 'should return that it was added to the cache' do
290
+ send_command('wadd sf 37.7830503 -122.3933962')
291
+ expect(replies.last)
292
+ .to eql 'sf added to the cache at [37.7830503, -122.3933962]'
293
+ end
294
+ end
295
+ end
296
+ end