croudia 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/.gitignore +17 -0
  2. data/Gemfile +4 -0
  3. data/LICENSE +22 -0
  4. data/README.md +29 -0
  5. data/Rakefile +2 -0
  6. data/croudia.gemspec +21 -0
  7. data/lib/croudia/api.rb +5 -0
  8. data/lib/croudia/identity.rb +39 -0
  9. data/lib/croudia/scraper/friendships.rb +33 -0
  10. data/lib/croudia/scraper/login.rb +40 -0
  11. data/lib/croudia/scraper/parser/users.rb +53 -0
  12. data/lib/croudia/scraper/parser/voices.rb +32 -0
  13. data/lib/croudia/scraper/parser.rb +13 -0
  14. data/lib/croudia/scraper/users.rb +20 -0
  15. data/lib/croudia/scraper/voices.rb +27 -0
  16. data/lib/croudia/scraper.rb +62 -0
  17. data/lib/croudia/user.rb +43 -0
  18. data/lib/croudia/version.rb +3 -0
  19. data/lib/croudia/voice.rb +21 -0
  20. data/lib/croudia.rb +23 -0
  21. data/spec/croudia/api_spec.rb +7 -0
  22. data/spec/croudia/identity_spec.rb +65 -0
  23. data/spec/croudia/scraper/friendships_spec.rb +61 -0
  24. data/spec/croudia/scraper/login_spec.rb +135 -0
  25. data/spec/croudia/scraper/parser/users_spec.rb +256 -0
  26. data/spec/croudia/scraper/parser/voices_spec.rb +119 -0
  27. data/spec/croudia/scraper/users_spec.rb +74 -0
  28. data/spec/croudia/scraper/voices_spec.rb +92 -0
  29. data/spec/croudia/scraper_spec.rb +120 -0
  30. data/spec/croudia/user_spec.rb +43 -0
  31. data/spec/croudia/version_spec.rb +7 -0
  32. data/spec/croudia/voice_spec.rb +16 -0
  33. data/spec/croudia_spec.rb +49 -0
  34. data/spec/fixtures/follower_wktk.html +89 -0
  35. data/spec/fixtures/following_wktk.html +89 -0
  36. data/spec/fixtures/user_wktk1.html +72 -0
  37. data/spec/fixtures/user_wktk2.html +75 -0
  38. data/spec/fixtures/user_wktk3.html +83 -0
  39. data/spec/fixtures/voices_reply_list.html +55 -0
  40. data/spec/fixtures/voices_timeline.html +60 -0
  41. data/spec/fixtures/voices_written.html +20 -0
  42. data/spec/helper.rb +32 -0
  43. metadata +157 -0
@@ -0,0 +1,135 @@
1
+ require 'helper'
2
+
3
+ describe Croudia::Scraper::Login do
4
+ describe '#login' do
5
+ before do
6
+ stub_get('/').to_return do |request|
7
+ if /logged_in=yes/ =~ request.headers['Cookie']
8
+ {:status => 302, :headers => {:location => Croudia.endpoint + '/logged_in'}}
9
+ else
10
+ {:headers => {:content_type => 'text/html'}}
11
+ end
12
+ end
13
+ stub_post('/').to_return do |request|
14
+ headers = {:content_type => 'text/html'}
15
+ if /username=username/ =~ request.body
16
+ headers.merge!(:set_cookie => 'logged_in=yes')
17
+ end
18
+ {:headers => headers}
19
+ end
20
+ stub_get('/logged_in').to_return(:headers => {:content_type => 'text/html'})
21
+ end
22
+
23
+ it 'gets "/" before login' do
24
+ Croudia::Scraper.new.login('username', 'password')
25
+ a_get('/').should have_been_made.twice
26
+ end
27
+
28
+ it 'posts the provided username and password to "/"' do
29
+ Croudia::Scraper.new.login('username', 'password')
30
+ a_post('/').with(:body => /username=username/).should have_been_made
31
+ end
32
+
33
+ it 'checks if succeeded or not' do
34
+ Croudia::Scraper.new.login('username', 'password')
35
+ a_get('/').with(:headers => {:cookie => /logged_in=yes/}).should have_been_made
36
+ end
37
+
38
+ context 'when the provided username and password are correct' do
39
+ it 'does not raise an error' do
40
+ expect{ Croudia::Scraper.new.login('username', 'password') }.not_to raise_error
41
+ end
42
+
43
+ it 'sets @logged_in as true' do
44
+ @croudia = Croudia::Scraper.new
45
+ @croudia.login('username', 'password')
46
+ @croudia.instance_variable_get('@logged_in').should be_true
47
+ end
48
+ end
49
+
50
+ context 'when the provided username and password are incorrect' do
51
+ it 'raises an error' do
52
+ expect{ Croudia::Scraper.new.login('wrong', 'wrong') }.to raise_error ArgumentError
53
+ end
54
+ end
55
+ end
56
+
57
+ describe '#logout' do
58
+ context 'when already logged out' do
59
+ it 'raises an error' do
60
+ @croudia = Croudia::Scraper.new
61
+ @croudia.instance_variable_set('@logged_in', false)
62
+ expect{ @croudia.logout }.to raise_error
63
+ end
64
+ end
65
+
66
+ context 'when logged in' do
67
+ before do
68
+ stub_post('/login/logout')
69
+ @croudia = Croudia::Scraper.new
70
+ @croudia.instance_variable_set('@logged_in', true)
71
+ end
72
+
73
+ it 'posts a request to the correct resource' do
74
+ @croudia.logout
75
+ a_post('/login/logout').should have_been_made
76
+ end
77
+
78
+ it 'sets @logged_in as false' do
79
+ @croudia.logout
80
+ @croudia.instance_variable_get('@logged_in').should be_false
81
+ end
82
+
83
+ it 'sets @current_user nil' do
84
+ @croudia.logout
85
+ @croudia.instance_variable_get('@current_user').should be_nil
86
+ end
87
+ end
88
+ end
89
+
90
+ describe '#logged_in?' do
91
+ context 'when @logged_in is set' do
92
+ it 'returns @logged_in' do
93
+ @croudia = Croudia::Scraper.new
94
+ @croudia.instance_variable_set('@logged_in', true)
95
+ @croudia.logged_in?.should be_true
96
+ @croudia.instance_variable_set('@logged_in', false)
97
+ @croudia.logged_in?.should be_false
98
+ end
99
+ end
100
+
101
+ context 'when @logged_in is not set' do
102
+ it 'gets "/" to confirm logged-in or not' do
103
+ stub_get('/')
104
+ Croudia::Scraper.new.logged_in?
105
+ a_get('/').should have_been_made
106
+ end
107
+ end
108
+ end
109
+
110
+ describe '#logged_out?' do
111
+ it 'returns !self.logged_in' do
112
+ @croudia = Croudia::Scraper.new
113
+ @croudia.instance_variable_set('@logged_in', true)
114
+ @croudia.logged_out?.should be_false
115
+ @croudia.instance_variable_set('@logged_in', false)
116
+ @croudia.logged_out?.should be_true
117
+ end
118
+ end
119
+
120
+ describe '#require_login' do
121
+ context 'when logged out' do
122
+ it 'raises an errror' do
123
+ expect{ Croudia::Scraper.new.require_login }.to raise_error
124
+ end
125
+ end
126
+
127
+ context 'when logged in' do
128
+ it 'does not raise an error' do
129
+ @croudia = Croudia::Scraper.new
130
+ @croudia.instance_variable_set('@logged_in', true)
131
+ expect{ @croudia.require_login }.not_to raise_error
132
+ end
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,256 @@
1
+ require 'helper'
2
+
3
+ describe Croudia::Scraper::Parser::Users do
4
+ describe '#user_page' do
5
+ context 'when it does not look like a user page' do
6
+ it 'returns nil' do
7
+ stub_get('/blank').to_return(:headers => {:content_type => 'text/html'})
8
+ Croudia.user('blank').should be_nil
9
+ end
10
+ end
11
+
12
+ context 'when it looks a user page' do
13
+ before do
14
+ stub_get('/wktk1').to_return(:body => fixture('user_wktk1'), :headers => {:content_type => 'text/html'})
15
+ @user1 = Croudia.user('wktk1')
16
+ stub_get('/wktk2').to_return(:body => fixture('user_wktk2'), :headers => {:content_type => 'text/html'})
17
+ @user2 = Croudia.user('wktk2')
18
+ stub_get('/wktk3').to_return(:body => fixture('user_wktk3'), :headers => {:content_type => 'text/html'})
19
+ @user3 = Croudia.user('wktk3')
20
+ end
21
+
22
+ it 'gets username' do
23
+ @user1.username.should eq 'wktk'
24
+ end
25
+
26
+ it 'gets nickname' do
27
+ @user1.nickname.should eq 'wktk!'
28
+ end
29
+
30
+ it 'gets avatar url' do
31
+ @user1.avatar.should eq 'https://croudia.com/testimages/download/9423'
32
+ end
33
+
34
+ it 'gets description' do
35
+ @user1.description.should eq 'This is a dummy description for test.'
36
+ end
37
+
38
+ it 'trims description' do
39
+ @user1.description.should_not match /^\s|\s$/
40
+ end
41
+
42
+ it 'gets voices_count' do
43
+ @user1.voices_count.to_i.should eq 3381
44
+ end
45
+
46
+ it 'converts voices_count into an Integer' do
47
+ @user1.voices_count.should be_a Integer
48
+ end
49
+
50
+ it 'gets following_count' do
51
+ @user1.following_count.to_i.should eq 46
52
+ end
53
+
54
+ it 'converts following_count into an Integer' do
55
+ @user1.following_count.should be_a Integer
56
+ end
57
+
58
+ it 'gets followers_count' do
59
+ @user1.followers_count.to_i.should eq 468
60
+ end
61
+
62
+ it 'converts followers_count into an Integer' do
63
+ @user1.followers_count.should be_a Integer
64
+ end
65
+
66
+ it 'gets album_count' do
67
+ @user1.album_count.to_i.should eq 123
68
+ end
69
+
70
+ it 'converts album_count into an Integer' do
71
+ @user1.album_count.should be_a Integer
72
+ end
73
+
74
+ it 'gets spreadia' do
75
+ @user1.spreadia.to_i.should eq 2525
76
+ end
77
+
78
+ it 'converts spreadia into an Integer' do
79
+ @user1.spreadia.should be_a Integer
80
+ end
81
+
82
+ it 'gets favodia' do
83
+ @user1.favodia.to_i.should eq 4321
84
+ end
85
+
86
+ it 'converts favodia into an Integer' do
87
+ @user1.favodia.should be_a Integer
88
+ end
89
+
90
+ context 'when url is set' do
91
+ it 'gets url' do
92
+ @user1.url.should eq 'http://wktk.in'
93
+ end
94
+ end
95
+
96
+ context 'when url is not set' do
97
+ it 'leaves url nil' do
98
+ @user2.url.should be_nil
99
+ end
100
+ end
101
+
102
+ context 'when location is set' do
103
+ it 'gets location' do
104
+ @user1.location.should eq 'Tokyo, Japan'
105
+ end
106
+ end
107
+
108
+ context 'when location is not set' do
109
+ it 'leaves location blank' do
110
+ @user2.location.should be_nil
111
+ end
112
+ end
113
+
114
+ context 'when following info included' do
115
+ context 'when following' do
116
+ it 'makes following true' do
117
+ @user2.following.should be_true
118
+ end
119
+ end
120
+
121
+ context 'when not following' do
122
+ it 'makes following false' do
123
+ @user3.following.should be_false
124
+ end
125
+ end
126
+ end
127
+
128
+ context 'when following info not included' do
129
+ it 'leaves following nil' do
130
+ @user1.following.should be_nil
131
+ end
132
+ end
133
+
134
+ context 'when followed_by info included' do
135
+ context 'when followed_by' do
136
+ it 'makes followed_by true' do
137
+ @user2.followed_by.should be_true
138
+ end
139
+ end
140
+
141
+ context 'when not followed_by' do
142
+ it 'makes followed_by false' do
143
+ @user3.followed_by.should be_false
144
+ end
145
+ end
146
+ end
147
+
148
+ context 'when followed_by info not included' do
149
+ it 'leaves followed_by nil' do
150
+ @user1.followed_by.should be_nil
151
+ end
152
+ end
153
+ end
154
+ end
155
+
156
+ describe '#user_list' do
157
+ before do
158
+ stub_get('/follows/following/wktk').to_return(:body => fixture('following_wktk'), :headers => {:content_type => 'text/html'})
159
+ stub_get('/follows/follower/wktk').to_return(:body => fixture('follower_wktk'), :headers => {:content_type => 'text/html'})
160
+ @following = Croudia.following('wktk')
161
+ @followers = Croudia.followers('wktk')
162
+ end
163
+
164
+ context 'when following list provided' do
165
+ it 'gets all users in the page' do
166
+ @following.size.should eq 3
167
+ end
168
+
169
+ it 'gets username' do
170
+ @following[0].username.should eq 'following1'
171
+ end
172
+
173
+ it 'gets nickname' do
174
+ @following[0].nickname.should eq 'following 1'
175
+ end
176
+
177
+ it 'gets avatar url' do
178
+ @following[0].avatar.should eq Croudia.endpoint + '/avatar1'
179
+ end
180
+
181
+ it 'gets description' do
182
+ @following[0].description.should eq 'Description 1'
183
+ end
184
+
185
+ it 'trims description' do
186
+ @following[0].description.should_not match /^\s|\s$/
187
+ end
188
+
189
+ context 'when following info provided' do
190
+ context 'when following' do
191
+ it 'sets following true' do
192
+ @following[0].following.should be_true
193
+ end
194
+ end
195
+
196
+ context 'when not following' do
197
+ it 'sets following false' do
198
+ @following[1].following.should be_false
199
+ end
200
+ end
201
+ end
202
+
203
+ context 'when following info not provided' do
204
+ it 'leaves following nil' do
205
+ @following[2].following.should be_false
206
+ end
207
+ end
208
+ end
209
+
210
+ context 'when follower list provided' do
211
+ it 'gets all users in the page' do
212
+ @followers.size.should eq 3
213
+ end
214
+
215
+ it 'gets username' do
216
+ @followers[0].username.should eq 'follower1'
217
+ end
218
+
219
+ it 'gets nickname' do
220
+ @followers[0].nickname.should eq 'follower 1'
221
+ end
222
+
223
+ it 'gets avatar url' do
224
+ @followers[0].avatar.should eq Croudia.endpoint + '/avatar1'
225
+ end
226
+
227
+ it 'gets description' do
228
+ @followers[0].description.should eq 'Description 1'
229
+ end
230
+
231
+ it 'trims description' do
232
+ @followers[0].description.should_not match /^\s|\s$/
233
+ end
234
+
235
+ context 'when following info provided' do
236
+ context 'when following' do
237
+ it 'sets following true' do
238
+ @followers[0].following.should be_true
239
+ end
240
+ end
241
+
242
+ context 'when not following' do
243
+ it 'sets following false' do
244
+ @followers[1].following.should be_false
245
+ end
246
+ end
247
+ end
248
+
249
+ context 'when following info not provided' do
250
+ it 'leaves following nil' do
251
+ @followers[2].following.should be_false
252
+ end
253
+ end
254
+ end
255
+ end
256
+ end
@@ -0,0 +1,119 @@
1
+ require 'helper'
2
+
3
+ describe Croudia::Scraper::Parser::Voices do
4
+ describe '#voices' do
5
+ context 'when parsing timeline' do
6
+ before do
7
+ stub_get('/voices/timeline').to_return(:body => fixture('voices_timeline'), :headers => {:content_type => 'text/html'})
8
+ @croudia = Croudia::Scraper.new
9
+ @croudia.instance_variable_set('@logged_in', true)
10
+ @timeline = @croudia.timeline
11
+ @voice = @timeline[0]
12
+ end
13
+
14
+ it 'returns an array' do
15
+ @timeline.should be_a Array
16
+ end
17
+
18
+ it 'returns an array of Croudia::Voice' do
19
+ @timeline.each do |voice|
20
+ voice.should be_a Croudia::Voice
21
+ end
22
+ end
23
+
24
+ it 'gets id' do
25
+ @voice.id.should eq '1001'
26
+ end
27
+
28
+ it 'gets user' do
29
+ @voice.user.username.should eq 'username1'
30
+ end
31
+
32
+ it 'user is a Croudia::User' do
33
+ @voice.user.should be_a Croudia::User
34
+ end
35
+
36
+ it 'gets text' do
37
+ @voice.text.should eq 'text 1'
38
+ end
39
+
40
+ it 'gets favorited_count' do
41
+ @voice.favorited_count.should eq 100
42
+ end
43
+
44
+ it 'converts favorited_count into an Integer' do
45
+ @voice.favorited_count.should be_a Integer
46
+ end
47
+
48
+ it 'gets spreaded_count' do
49
+ @voice.spreaded_count.should eq 950
50
+ end
51
+
52
+ it 'converts spreaded_count into an Integer' do
53
+ @voice.spreaded_count.should be_a Integer
54
+ end
55
+
56
+ it 'gets time' do
57
+ @voice.time.should eq Time.at(1356250231)
58
+ end
59
+
60
+ it 'converts time into a Time' do
61
+ if (@voice.time)
62
+ @voice.time.should be_a Time
63
+ end
64
+ end
65
+ end
66
+
67
+ context 'when parsing reply_list' do
68
+ before do
69
+ stub_get('/voices/reply_list').to_return(:body => fixture('voices_reply_list'), :headers => {:content_type => 'text/html'})
70
+ @croudia = Croudia::Scraper.new
71
+ @croudia.instance_variable_set('@logged_in', true)
72
+ @reply_list = @croudia.reply_list
73
+ @voice = @reply_list[0]
74
+ end
75
+
76
+ it 'returns an array' do
77
+ @reply_list.should be_a Array
78
+ end
79
+
80
+ it 'returns an array of Croudia::Voice' do
81
+ @reply_list.each do |voice|
82
+ voice.should be_a Croudia::Voice
83
+ end
84
+ end
85
+
86
+ it 'gets id' do
87
+ @voice.id.should eq '1001'
88
+ end
89
+
90
+ it 'gets user' do
91
+ @voice.user.username.should eq 'wktk'
92
+ end
93
+
94
+ it 'user is a Croudia::User' do
95
+ @voice.user.should be_a Croudia::User
96
+ end
97
+
98
+ it 'gets text' do
99
+ @voice.text.should eq '@wktk wktk! wktk! wktk! (^-^)/'
100
+ end
101
+
102
+ it 'gets favorited_count' do
103
+ @voice.favorited_count.should eq 500
104
+ end
105
+
106
+ it 'converts favorited_count into an Integer' do
107
+ @voice.favorited_count.should be_a Integer
108
+ end
109
+
110
+ it 'gets spreaded_count' do
111
+ @voice.spreaded_count.should eq 1000
112
+ end
113
+
114
+ it 'converts spreaded_count into an Integer' do
115
+ @voice.spreaded_count.should be_a Integer
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,74 @@
1
+ require 'helper'
2
+
3
+ describe Croudia::Scraper::Users do
4
+ describe '#current_user' do
5
+ context 'when logged in' do
6
+ before do
7
+ @croudia = Croudia::Scraper.new
8
+ @croudia.instance_variable_set('@logged_in', true)
9
+ stub_get('/users/redirect_user').to_return(:body => fixture('user_wktk1'), :headers => {:content_type => 'text/html'})
10
+ end
11
+
12
+ it 'gets the correct resource' do
13
+ @croudia.current_user
14
+ a_get('/users/redirect_user').should have_been_made
15
+ end
16
+
17
+ it 'returns an object of the current user' do
18
+ @croudia.current_user.should be_a Croudia::User
19
+ end
20
+
21
+ it 'caches @current_user' do
22
+ @croudia.current_user
23
+ @croudia.current_user
24
+ a_get('/users/redirect_user').should have_been_made.once
25
+ end
26
+
27
+ it 'returns the cached object if exists' do
28
+ @current_user = @croudia.current_user
29
+ @croudia.current_user.object_id.should eq @current_user.object_id
30
+ end
31
+
32
+ it 'destroyes the cache when an true argument provided' do
33
+ @croudia.current_user(true)
34
+ a_get('/users/redirect_user').should have_been_made
35
+ end
36
+ end
37
+
38
+ context 'when not logged in' do
39
+ it 'raises an error' do
40
+ expect{ Croudia::Scraper.new.current_user }.to raise_error
41
+ end
42
+ end
43
+ end
44
+
45
+ describe '#user' do
46
+ context 'when an argument provided' do
47
+ before do
48
+ stub_get('/wktk').to_return(:body => fixture('user_wktk1'), :headers => {:content_type => 'text/html'})
49
+ end
50
+
51
+ it 'gets the correct resource' do
52
+ Croudia::Scraper.new.user('wktk')
53
+ a_get('/wktk').should have_been_made
54
+ end
55
+
56
+ it 'returns a user object' do
57
+ Croudia::Scraper.new.user('wktk').should be_a Croudia::User
58
+ end
59
+ end
60
+
61
+ context 'when arguments not provided' do
62
+ it 'returns @current_user when logged in' do
63
+ @croudia = Croudia::Scraper.new
64
+ @croudia.instance_variable_set('@current_user', Croudia::User.new(:username => 'current_user'))
65
+ @croudia.instance_variable_set('@logged_in', true)
66
+ @croudia.user.to_s.should eq 'current_user'
67
+ end
68
+
69
+ it 'raises an error when not logged in' do
70
+ expect{ Croudia::Scraper.new.user }.to raise_error
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,92 @@
1
+ require 'helper'
2
+
3
+ describe Croudia::Scraper::Voices do
4
+ describe '#timeline' do
5
+ context 'when logged in' do
6
+ before do
7
+ stub_get('/voices/timeline').to_return(:body => fixture('voices_timeline'), :headers => {:content_type => 'text/html'})
8
+ @croudia = Croudia::Scraper.new
9
+ @croudia.instance_variable_set('@logged_in', true)
10
+ end
11
+
12
+ it 'does not raise an error' do
13
+ expect{ @croudia.timeline }.not_to raise_error
14
+ end
15
+
16
+ it 'gets the correct resource' do
17
+ @croudia.timeline
18
+ a_get('/voices/timeline').should have_been_made
19
+ end
20
+
21
+ it 'returns an array' do
22
+ @croudia.timeline.should be_a Array
23
+ end
24
+
25
+ it 'returns an array of Croudia::Voice' do
26
+ @croudia.timeline.each do |voice|
27
+ voice.should be_a Croudia::Voice
28
+ end
29
+ end
30
+ end
31
+
32
+ context 'when not logged in' do
33
+ it 'raises an error' do
34
+ expect{ Croudia::Scraper.new.timeline }.to raise_error
35
+ end
36
+ end
37
+ end
38
+
39
+ describe '#reply_list' do
40
+ context 'when logged in' do
41
+ before do
42
+ stub_get('/voices/reply_list').to_return(:body => fixture('voices_reply_list'), :headers => {:content_type => 'text/html'})
43
+ @croudia = Croudia::Scraper.new
44
+ @croudia.instance_variable_set('@logged_in', true)
45
+ end
46
+
47
+ it 'does not raise an error' do
48
+ expect{ @croudia.reply_list }.not_to raise_error
49
+ end
50
+
51
+ it 'gets the correct resource' do
52
+ @croudia.reply_list
53
+ a_get('/voices/reply_list').should have_been_made
54
+ end
55
+
56
+ it 'returns an array of Croudia::Voice' do
57
+ @croudia.reply_list.each do |voice|
58
+ voice.should be_a Croudia::Voice
59
+ end
60
+ end
61
+ end
62
+
63
+ context 'when not logged in' do
64
+ it 'raises an error' do
65
+ expect{ Croudia::Scraper.new.reply_list }.to raise_error
66
+ end
67
+ end
68
+ end
69
+
70
+ describe '#update' do
71
+ context 'when not logged in' do
72
+ it 'raises an error' do
73
+ expect{ Croudia::Scraper.new.update('Hi') }.to raise_error
74
+ end
75
+ end
76
+
77
+ context 'when logged in' do
78
+ before do
79
+ stub_get('/voices/written').to_return(:body => fixture('voices_written'), :headers => {:content_type => 'text/html'})
80
+ stub_post('/voices/write').to_return(:headers => {:content_type => 'text/html'})
81
+ @croudia = Croudia::Scraper.new
82
+ @croudia.instance_variable_set('@logged_in', true)
83
+ end
84
+
85
+ it 'posts to the correct resource' do
86
+ @croudia.update('Hello')
87
+ a_get('/voices/written').should have_been_made
88
+ a_post('/voices/write').should have_been_made
89
+ end
90
+ end
91
+ end
92
+ end