neocoin-mechanize 2.0.2

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 (174) hide show
  1. data/.autotest +6 -0
  2. data/.gemtest +0 -0
  3. data/CHANGELOG.rdoc +638 -0
  4. data/EXAMPLES.rdoc +187 -0
  5. data/FAQ.rdoc +11 -0
  6. data/GUIDE.rdoc +163 -0
  7. data/LICENSE.rdoc +20 -0
  8. data/Manifest.txt +172 -0
  9. data/README.rdoc +63 -0
  10. data/Rakefile +36 -0
  11. data/examples/flickr_upload.rb +22 -0
  12. data/examples/mech-dump.rb +5 -0
  13. data/examples/proxy_req.rb +7 -0
  14. data/examples/rubyforge.rb +20 -0
  15. data/examples/spider.rb +21 -0
  16. data/lib/mechanize.rb +662 -0
  17. data/lib/mechanize/content_type_error.rb +14 -0
  18. data/lib/mechanize/cookie.rb +85 -0
  19. data/lib/mechanize/cookie_jar.rb +241 -0
  20. data/lib/mechanize/element_matcher.rb +35 -0
  21. data/lib/mechanize/file.rb +80 -0
  22. data/lib/mechanize/file_connection.rb +17 -0
  23. data/lib/mechanize/file_request.rb +26 -0
  24. data/lib/mechanize/file_response.rb +74 -0
  25. data/lib/mechanize/file_saver.rb +37 -0
  26. data/lib/mechanize/form.rb +478 -0
  27. data/lib/mechanize/form/button.rb +9 -0
  28. data/lib/mechanize/form/check_box.rb +11 -0
  29. data/lib/mechanize/form/field.rb +44 -0
  30. data/lib/mechanize/form/file_upload.rb +23 -0
  31. data/lib/mechanize/form/image_button.rb +20 -0
  32. data/lib/mechanize/form/multi_select_list.rb +83 -0
  33. data/lib/mechanize/form/option.rb +49 -0
  34. data/lib/mechanize/form/radio_button.rb +48 -0
  35. data/lib/mechanize/form/select_list.rb +40 -0
  36. data/lib/mechanize/headers.rb +25 -0
  37. data/lib/mechanize/history.rb +83 -0
  38. data/lib/mechanize/http.rb +3 -0
  39. data/lib/mechanize/http/agent.rb +738 -0
  40. data/lib/mechanize/inspect.rb +88 -0
  41. data/lib/mechanize/monkey_patch.rb +37 -0
  42. data/lib/mechanize/page.rb +408 -0
  43. data/lib/mechanize/page/base.rb +8 -0
  44. data/lib/mechanize/page/frame.rb +27 -0
  45. data/lib/mechanize/page/image.rb +30 -0
  46. data/lib/mechanize/page/label.rb +20 -0
  47. data/lib/mechanize/page/link.rb +82 -0
  48. data/lib/mechanize/page/meta_refresh.rb +56 -0
  49. data/lib/mechanize/pluggable_parsers.rb +101 -0
  50. data/lib/mechanize/redirect_limit_reached_error.rb +16 -0
  51. data/lib/mechanize/redirect_not_get_or_head_error.rb +19 -0
  52. data/lib/mechanize/response_code_error.rb +22 -0
  53. data/lib/mechanize/response_read_error.rb +27 -0
  54. data/lib/mechanize/robots_disallowed_error.rb +29 -0
  55. data/lib/mechanize/unsupported_scheme_error.rb +8 -0
  56. data/lib/mechanize/util.rb +113 -0
  57. data/test/data/htpasswd +1 -0
  58. data/test/data/server.crt +16 -0
  59. data/test/data/server.csr +12 -0
  60. data/test/data/server.key +15 -0
  61. data/test/data/server.pem +15 -0
  62. data/test/helper.rb +175 -0
  63. data/test/htdocs/alt_text.html +10 -0
  64. data/test/htdocs/bad_form_test.html +9 -0
  65. data/test/htdocs/button.jpg +0 -0
  66. data/test/htdocs/canonical_uri.html +9 -0
  67. data/test/htdocs/dir with spaces/foo.html +1 -0
  68. data/test/htdocs/empty_form.html +6 -0
  69. data/test/htdocs/file_upload.html +26 -0
  70. data/test/htdocs/find_link.html +41 -0
  71. data/test/htdocs/form_multi_select.html +16 -0
  72. data/test/htdocs/form_multival.html +37 -0
  73. data/test/htdocs/form_no_action.html +18 -0
  74. data/test/htdocs/form_no_input_name.html +16 -0
  75. data/test/htdocs/form_select.html +16 -0
  76. data/test/htdocs/form_select_all.html +16 -0
  77. data/test/htdocs/form_select_none.html +17 -0
  78. data/test/htdocs/form_select_noopts.html +10 -0
  79. data/test/htdocs/form_set_fields.html +14 -0
  80. data/test/htdocs/form_test.html +188 -0
  81. data/test/htdocs/frame_referer_test.html +10 -0
  82. data/test/htdocs/frame_test.html +30 -0
  83. data/test/htdocs/google.html +13 -0
  84. data/test/htdocs/iframe_test.html +16 -0
  85. data/test/htdocs/index.html +6 -0
  86. data/test/htdocs/link with space.html +5 -0
  87. data/test/htdocs/meta_cookie.html +11 -0
  88. data/test/htdocs/no_title_test.html +6 -0
  89. data/test/htdocs/nofollow.html +9 -0
  90. data/test/htdocs/noindex.html +9 -0
  91. data/test/htdocs/norobots.html +8 -0
  92. data/test/htdocs/rails_3_encoding_hack_form_test.html +27 -0
  93. data/test/htdocs/rel_nofollow.html +8 -0
  94. data/test/htdocs/relative/tc_relative_links.html +21 -0
  95. data/test/htdocs/robots.html +8 -0
  96. data/test/htdocs/robots.txt +2 -0
  97. data/test/htdocs/tc_bad_charset.html +9 -0
  98. data/test/htdocs/tc_bad_links.html +5 -0
  99. data/test/htdocs/tc_base_images.html +10 -0
  100. data/test/htdocs/tc_base_link.html +8 -0
  101. data/test/htdocs/tc_blank_form.html +11 -0
  102. data/test/htdocs/tc_charset.html +6 -0
  103. data/test/htdocs/tc_checkboxes.html +19 -0
  104. data/test/htdocs/tc_encoded_links.html +5 -0
  105. data/test/htdocs/tc_field_precedence.html +11 -0
  106. data/test/htdocs/tc_follow_meta.html +8 -0
  107. data/test/htdocs/tc_form_action.html +48 -0
  108. data/test/htdocs/tc_images.html +8 -0
  109. data/test/htdocs/tc_links.html +18 -0
  110. data/test/htdocs/tc_meta_in_body.html +9 -0
  111. data/test/htdocs/tc_no_attributes.html +16 -0
  112. data/test/htdocs/tc_pretty_print.html +17 -0
  113. data/test/htdocs/tc_radiobuttons.html +17 -0
  114. data/test/htdocs/tc_referer.html +16 -0
  115. data/test/htdocs/tc_relative_links.html +19 -0
  116. data/test/htdocs/tc_textarea.html +23 -0
  117. data/test/htdocs/test_bad_encoding.html +52 -0
  118. data/test/htdocs/test_click.html +11 -0
  119. data/test/htdocs/unusual______.html +5 -0
  120. data/test/servlets.rb +402 -0
  121. data/test/ssl_server.rb +48 -0
  122. data/test/test_cookies.rb +129 -0
  123. data/test/test_form_action.rb +52 -0
  124. data/test/test_form_as_hash.rb +59 -0
  125. data/test/test_form_button.rb +46 -0
  126. data/test/test_frames.rb +34 -0
  127. data/test/test_headers.rb +33 -0
  128. data/test/test_history.rb +118 -0
  129. data/test/test_history_added.rb +16 -0
  130. data/test/test_html_unscape_forms.rb +46 -0
  131. data/test/test_if_modified_since.rb +20 -0
  132. data/test/test_images.rb +19 -0
  133. data/test/test_mechanize.rb +842 -0
  134. data/test/test_mechanize_cookie.rb +345 -0
  135. data/test/test_mechanize_cookie_jar.rb +401 -0
  136. data/test/test_mechanize_file.rb +53 -0
  137. data/test/test_mechanize_file_request.rb +19 -0
  138. data/test/test_mechanize_file_response.rb +21 -0
  139. data/test/test_mechanize_form.rb +576 -0
  140. data/test/test_mechanize_form_check_box.rb +37 -0
  141. data/test/test_mechanize_form_encoding.rb +120 -0
  142. data/test/test_mechanize_form_field.rb +21 -0
  143. data/test/test_mechanize_form_image_button.rb +12 -0
  144. data/test/test_mechanize_form_textarea.rb +51 -0
  145. data/test/test_mechanize_http_agent.rb +697 -0
  146. data/test/test_mechanize_link.rb +84 -0
  147. data/test/test_mechanize_page_encoding.rb +147 -0
  148. data/test/test_mechanize_page_link.rb +382 -0
  149. data/test/test_mechanize_page_meta_refresh.rb +115 -0
  150. data/test/test_mechanize_redirect_not_get_or_head_error.rb +18 -0
  151. data/test/test_mechanize_subclass.rb +22 -0
  152. data/test/test_mechanize_util.rb +92 -0
  153. data/test/test_multi_select.rb +118 -0
  154. data/test/test_no_attributes.rb +13 -0
  155. data/test/test_option.rb +18 -0
  156. data/test/test_pluggable_parser.rb +136 -0
  157. data/test/test_post_form.rb +37 -0
  158. data/test/test_pretty_print.rb +22 -0
  159. data/test/test_radiobutton.rb +75 -0
  160. data/test/test_redirect_limit_reached.rb +39 -0
  161. data/test/test_referer.rb +81 -0
  162. data/test/test_relative_links.rb +40 -0
  163. data/test/test_request.rb +13 -0
  164. data/test/test_response_code.rb +53 -0
  165. data/test/test_robots.rb +72 -0
  166. data/test/test_save_file.rb +48 -0
  167. data/test/test_scheme.rb +48 -0
  168. data/test/test_select.rb +119 -0
  169. data/test/test_select_all.rb +15 -0
  170. data/test/test_select_none.rb +15 -0
  171. data/test/test_select_noopts.rb +18 -0
  172. data/test/test_set_fields.rb +44 -0
  173. data/test/test_ssl_server.rb +20 -0
  174. metadata +354 -0
@@ -0,0 +1,345 @@
1
+ require "helper"
2
+
3
+ module Enumerable
4
+ def combine
5
+ masks = inject([[], 1]){|(ar, m), e| [ar << m, m << 1 ] }[0]
6
+ all = masks.inject(0){ |al, m| al|m }
7
+
8
+ result = []
9
+ for i in 1..all do
10
+ tmp = []
11
+ each_with_index do |e, idx|
12
+ tmp << e unless (masks[idx] & i) == 0
13
+ end
14
+ result << tmp
15
+ end
16
+ result
17
+ end
18
+ end
19
+
20
+ class TestMechanizeCookie < MiniTest::Unit::TestCase
21
+ def silently
22
+ warn_level = $VERBOSE
23
+ $VERBOSE = false
24
+ res = yield
25
+ $VERBOSE = warn_level
26
+ res
27
+ end
28
+
29
+ def test_parse_dates
30
+ url = URI.parse('http://localhost/')
31
+
32
+ yesterday = Time.now - 86400
33
+
34
+ dates = [ "14 Apr 89 03:20:12",
35
+ "14 Apr 89 03:20 GMT",
36
+ "Fri, 17 Mar 89 4:01:33",
37
+ "Fri, 17 Mar 89 4:01 GMT",
38
+ "Mon Jan 16 16:12 PDT 1989",
39
+ "Mon Jan 16 16:12 +0130 1989",
40
+ "6 May 1992 16:41-JST (Wednesday)",
41
+ #"22-AUG-1993 10:59:12.82",
42
+ "22-AUG-1993 10:59pm",
43
+ "22-AUG-1993 12:59am",
44
+ "22-AUG-1993 12:59 PM",
45
+ #"Friday, August 04, 1995 3:54 PM",
46
+ #"06/21/95 04:24:34 PM",
47
+ #"20/06/95 21:07",
48
+ "95-06-08 19:32:48 EDT",
49
+ ]
50
+
51
+ dates.each do |date|
52
+ cookie = "PREF=1; expires=#{date}"
53
+ silently do
54
+ Mechanize::Cookie.parse(url, cookie) { |c|
55
+ assert c.expires, "Tried parsing: #{date}"
56
+ assert_equal(true, c.expires < yesterday)
57
+ }
58
+ end
59
+ end
60
+ end
61
+
62
+ def test_parse_empty
63
+ cookie_str = 'a=b; ; c=d'
64
+
65
+ uri = URI.parse 'http://example'
66
+
67
+ Mechanize::Cookie.parse uri, cookie_str do |cookie|
68
+ assert_equal 'a', cookie.name
69
+ assert_equal 'b', cookie.value
70
+ end
71
+ end
72
+
73
+ def test_parse_weird_cookie
74
+ cookie = 'n/a, ASPSESSIONIDCSRRQDQR=FBLDGHPBNDJCPCGNCPAENELB; path=/'
75
+ url = URI.parse('http://www.searchinnovation.com/')
76
+ Mechanize::Cookie.parse(url, cookie) { |c|
77
+ assert_equal('ASPSESSIONIDCSRRQDQR', c.name)
78
+ assert_equal('FBLDGHPBNDJCPCGNCPAENELB', c.value)
79
+ }
80
+ end
81
+
82
+ def test_double_semicolon
83
+ double_semi = 'WSIDC=WEST;; domain=.williams-sonoma.com; path=/'
84
+ url = URI.parse('http://williams-sonoma.com/')
85
+ Mechanize::Cookie.parse(url, double_semi) { |cookie|
86
+ assert_equal('WSIDC', cookie.name)
87
+ assert_equal('WEST', cookie.value)
88
+ }
89
+ end
90
+
91
+ def test_parse_bad_version
92
+ bad_cookie = 'PRETANET=TGIAqbFXtt; Name=/PRETANET; Path=/; Version=1.2; Content-type=text/html; Domain=192.168.6.196; expires=Friday, 13-November-2026 23:01:46 GMT;'
93
+ url = URI.parse('http://localhost/')
94
+ Mechanize::Cookie.parse(url, bad_cookie) { |cookie|
95
+ assert_nil(cookie.version)
96
+ }
97
+ end
98
+
99
+ def test_parse_bad_max_age
100
+ bad_cookie = 'PRETANET=TGIAqbFXtt; Name=/PRETANET; Path=/; Max-Age=1.2; Content-type=text/html; Domain=192.168.6.196; expires=Friday, 13-November-2026 23:01:46 GMT;'
101
+ url = URI.parse('http://localhost/')
102
+ Mechanize::Cookie.parse(url, bad_cookie) { |cookie|
103
+ assert_nil(cookie.max_age)
104
+ }
105
+ end
106
+
107
+ def test_parse_date_fail
108
+ url = URI.parse('http://localhost/')
109
+
110
+ dates = [
111
+ "20/06/95 21:07",
112
+ ]
113
+
114
+ silently do
115
+ dates.each do |date|
116
+ cookie = "PREF=1; expires=#{date}"
117
+ Mechanize::Cookie.parse(url, cookie) { |c|
118
+ assert_equal(true, c.expires.nil?)
119
+ }
120
+ end
121
+ end
122
+ end
123
+
124
+ def test_parse_domain_dot
125
+ url = URI.parse('http://host.example.com/')
126
+
127
+ cookie_str = 'a=b; domain=.example.com'
128
+
129
+ cookie = Mechanize::Cookie.parse(url, cookie_str).first
130
+
131
+ assert_equal '.example.com', cookie.domain
132
+ end
133
+
134
+ def test_parse_domain_no_dot
135
+ url = URI.parse('http://host.example.com/')
136
+
137
+ cookie_str = 'a=b; domain=example.com'
138
+
139
+ cookie = Mechanize::Cookie.parse(url, cookie_str).first
140
+
141
+ assert_equal '.example.com', cookie.domain
142
+ end
143
+
144
+ def test_parse_domain_none
145
+ url = URI.parse('http://example.com/')
146
+
147
+ cookie_str = 'a=b;'
148
+
149
+ cookie = Mechanize::Cookie.parse(url, cookie_str).first
150
+
151
+ assert_equal 'example.com', cookie.domain
152
+ end
153
+
154
+ def test_parse_expires_session
155
+ cookie = 'PRETANET=TGIAqbFXtt; Name=/PRETANET; Path=/; Max-Age=1.2; Content-type=text/html; Domain=192.168.6.196; expires=;'
156
+
157
+ url = URI.parse('http://localhost/')
158
+
159
+ cookie = Mechanize::Cookie.parse(url, cookie).first
160
+
161
+ assert cookie.session
162
+ end
163
+
164
+ def test_parse_valid_cookie
165
+ url = URI.parse('http://rubyforge.org/')
166
+ cookie_params = {}
167
+ cookie_params['expires'] = 'expires=Sun, 27-Sep-2037 00:00:00 GMT'
168
+ cookie_params['path'] = 'path=/'
169
+ cookie_params['domain'] = 'domain=.rubyforge.org'
170
+ cookie_params['httponly'] = 'HttpOnly'
171
+ cookie_value = '12345%7D=ASDFWEE345%3DASda'
172
+
173
+ expires = Time.parse('Sun, 27-Sep-2037 00:00:00 GMT')
174
+
175
+ cookie_params.keys.combine.each do |c|
176
+ cookie_text = "#{cookie_value}; "
177
+ c.each_with_index do |key, idx|
178
+ if idx == (c.length - 1)
179
+ cookie_text << "#{cookie_params[key]}"
180
+ else
181
+ cookie_text << "#{cookie_params[key]}; "
182
+ end
183
+ end
184
+ cookie = nil
185
+ Mechanize::Cookie.parse(url, cookie_text) { |p_cookie| cookie = p_cookie }
186
+
187
+ assert_equal('12345%7D=ASDFWEE345%3DASda', cookie.to_s)
188
+ assert_equal('/', cookie.path)
189
+
190
+ # if expires was set, make sure we parsed it
191
+ if c.find { |k| k == 'expires' }
192
+ assert_equal(expires, cookie.expires)
193
+ else
194
+ assert_nil(cookie.expires)
195
+ end
196
+ end
197
+ end
198
+
199
+ def test_parse_valid_cookie_empty_value
200
+ url = URI.parse('http://rubyforge.org/')
201
+ cookie_params = {}
202
+ cookie_params['expires'] = 'expires=Sun, 27-Sep-2037 00:00:00 GMT'
203
+ cookie_params['path'] = 'path=/'
204
+ cookie_params['domain'] = 'domain=.rubyforge.org'
205
+ cookie_params['httponly'] = 'HttpOnly'
206
+ cookie_value = '12345%7D='
207
+
208
+ expires = Time.parse('Sun, 27-Sep-2037 00:00:00 GMT')
209
+
210
+ cookie_params.keys.combine.each do |c|
211
+ cookie_text = "#{cookie_value}; "
212
+ c.each_with_index do |key, idx|
213
+ if idx == (c.length - 1)
214
+ cookie_text << "#{cookie_params[key]}"
215
+ else
216
+ cookie_text << "#{cookie_params[key]}; "
217
+ end
218
+ end
219
+ cookie = nil
220
+ Mechanize::Cookie.parse(url, cookie_text) { |p_cookie| cookie = p_cookie }
221
+
222
+ assert_equal('12345%7D=', cookie.to_s)
223
+ assert_equal('', cookie.value)
224
+ assert_equal('/', cookie.path)
225
+
226
+ # if expires was set, make sure we parsed it
227
+ if c.find { |k| k == 'expires' }
228
+ assert_equal(expires, cookie.expires)
229
+ else
230
+ assert_nil(cookie.expires)
231
+ end
232
+ end
233
+ end
234
+
235
+ # If no path was given, use the one from the URL
236
+ def test_cookie_using_url_path
237
+ url = URI.parse('http://rubyforge.org/login.php')
238
+ cookie_params = {}
239
+ cookie_params['expires'] = 'expires=Sun, 27-Sep-2037 00:00:00 GMT'
240
+ cookie_params['path'] = 'path=/'
241
+ cookie_params['domain'] = 'domain=.rubyforge.org'
242
+ cookie_params['httponly'] = 'HttpOnly'
243
+ cookie_value = '12345%7D=ASDFWEE345%3DASda'
244
+
245
+ expires = Time.parse('Sun, 27-Sep-2037 00:00:00 GMT')
246
+
247
+ cookie_params.keys.combine.each do |c|
248
+ next if c.find { |k| k == 'path' }
249
+ cookie_text = "#{cookie_value}; "
250
+ c.each_with_index do |key, idx|
251
+ if idx == (c.length - 1)
252
+ cookie_text << "#{cookie_params[key]}"
253
+ else
254
+ cookie_text << "#{cookie_params[key]}; "
255
+ end
256
+ end
257
+ cookie = nil
258
+ Mechanize::Cookie.parse(url, cookie_text) { |p_cookie| cookie = p_cookie }
259
+
260
+ assert_equal('12345%7D=ASDFWEE345%3DASda', cookie.to_s)
261
+ assert_equal('/', cookie.path)
262
+
263
+ # if expires was set, make sure we parsed it
264
+ if c.find { |k| k == 'expires' }
265
+ assert_equal(expires, cookie.expires)
266
+ else
267
+ assert_nil(cookie.expires)
268
+ end
269
+ end
270
+ end
271
+
272
+ # Test using secure cookies
273
+ def test_cookie_with_secure
274
+ url = URI.parse('http://rubyforge.org/')
275
+ cookie_params = {}
276
+ cookie_params['expires'] = 'expires=Sun, 27-Sep-2037 00:00:00 GMT'
277
+ cookie_params['path'] = 'path=/'
278
+ cookie_params['domain'] = 'domain=.rubyforge.org'
279
+ cookie_params['secure'] = 'secure'
280
+ cookie_value = '12345%7D=ASDFWEE345%3DASda'
281
+
282
+ expires = Time.parse('Sun, 27-Sep-2037 00:00:00 GMT')
283
+
284
+ cookie_params.keys.combine.each do |c|
285
+ next unless c.find { |k| k == 'secure' }
286
+ cookie_text = "#{cookie_value}; "
287
+ c.each_with_index do |key, idx|
288
+ if idx == (c.length - 1)
289
+ cookie_text << "#{cookie_params[key]}"
290
+ else
291
+ cookie_text << "#{cookie_params[key]}; "
292
+ end
293
+ end
294
+ cookie = nil
295
+ Mechanize::Cookie.parse(url, cookie_text) { |p_cookie| cookie = p_cookie }
296
+
297
+ assert_equal('12345%7D=ASDFWEE345%3DASda', cookie.to_s)
298
+ assert_equal('/', cookie.path)
299
+ assert_equal(true, cookie.secure)
300
+
301
+ # if expires was set, make sure we parsed it
302
+ if c.find { |k| k == 'expires' }
303
+ assert_equal(expires, cookie.expires)
304
+ else
305
+ assert_nil(cookie.expires)
306
+ end
307
+ end
308
+ end
309
+
310
+ def test_parse_cookie_no_spaces
311
+ url = URI.parse('http://rubyforge.org/')
312
+ cookie_params = {}
313
+ cookie_params['expires'] = 'expires=Sun, 27-Sep-2037 00:00:00 GMT'
314
+ cookie_params['path'] = 'path=/'
315
+ cookie_params['domain'] = 'domain=.rubyforge.org'
316
+ cookie_params['httponly'] = 'HttpOnly'
317
+ cookie_value = '12345%7D=ASDFWEE345%3DASda'
318
+
319
+ expires = Time.parse('Sun, 27-Sep-2037 00:00:00 GMT')
320
+
321
+ cookie_params.keys.combine.each do |c|
322
+ cookie_text = "#{cookie_value};"
323
+ c.each_with_index do |key, idx|
324
+ if idx == (c.length - 1)
325
+ cookie_text << "#{cookie_params[key]}"
326
+ else
327
+ cookie_text << "#{cookie_params[key]};"
328
+ end
329
+ end
330
+ cookie = nil
331
+ Mechanize::Cookie.parse(url, cookie_text) { |p_cookie| cookie = p_cookie }
332
+
333
+ assert_equal('12345%7D=ASDFWEE345%3DASda', cookie.to_s)
334
+ assert_equal('/', cookie.path)
335
+
336
+ # if expires was set, make sure we parsed it
337
+ if c.find { |k| k == 'expires' }
338
+ assert_equal(expires, cookie.expires)
339
+ else
340
+ assert_nil(cookie.expires)
341
+ end
342
+ end
343
+ end
344
+ end
345
+
@@ -0,0 +1,401 @@
1
+ require 'helper'
2
+ require 'tmpdir'
3
+
4
+ class TestMechanizeCookieJar < MiniTest::Unit::TestCase
5
+
6
+ def setup
7
+ @jar = Mechanize::CookieJar.new
8
+ @tmpdir = Dir.mktmpdir
9
+
10
+ @orig_dir = Dir.pwd
11
+ Dir.chdir @tmpdir
12
+ end
13
+
14
+ def teardown
15
+ Dir.chdir @orig_dir
16
+ FileUtils.remove_entry_secure @tmpdir
17
+ end
18
+
19
+ def cookie_values(options = {})
20
+ {
21
+ :name => 'Foo',
22
+ :value => 'Bar',
23
+ :path => '/',
24
+ :expires => Time.now + (10 * 86400),
25
+ :domain => 'rubyforge.org'
26
+ }.merge(options)
27
+ end
28
+
29
+ def cookie_from_hash(hash)
30
+ c = Mechanize::Cookie.new(hash[:name], hash[:value])
31
+ hash.each { |k,v|
32
+ next if k == :name || k == :value
33
+ c.send("#{k}=", v)
34
+ }
35
+ c
36
+ end
37
+
38
+ def test_two_cookies_same_domain_and_name_different_paths
39
+ url = URI.parse('http://rubyforge.org/')
40
+
41
+ cookie = cookie_from_hash(cookie_values)
42
+ @jar.add(url, cookie)
43
+ @jar.add(url, cookie_from_hash(cookie_values(:path => '/onetwo')))
44
+
45
+ assert_equal(1, @jar.cookies(url).length)
46
+ assert_equal 2, @jar.cookies(URI.parse('http://rubyforge.org/onetwo')).length
47
+ end
48
+
49
+ def test_domain_case
50
+ url = URI.parse('http://rubyforge.org/')
51
+
52
+ # Add one cookie with an expiration date in the future
53
+ cookie = cookie_from_hash(cookie_values)
54
+ @jar.add(url, cookie)
55
+ assert_equal(1, @jar.cookies(url).length)
56
+
57
+ @jar.add(url, cookie_from_hash(
58
+ cookie_values(:domain => 'RuByForge.Org', :name => 'aaron')))
59
+
60
+ assert_equal(2, @jar.cookies(url).length)
61
+
62
+ url2 = URI.parse('http://RuByFoRgE.oRg/')
63
+ assert_equal(2, @jar.cookies(url2).length)
64
+ end
65
+
66
+ def test_empty_value
67
+ values = cookie_values(:value => "")
68
+ url = URI.parse('http://rubyforge.org/')
69
+
70
+ # Add one cookie with an expiration date in the future
71
+ cookie = cookie_from_hash(values)
72
+ @jar.add(url, cookie)
73
+ assert_equal(1, @jar.cookies(url).length)
74
+
75
+ @jar.add(url, cookie_from_hash( values.merge( :domain => 'RuByForge.Org',
76
+ :name => 'aaron'
77
+ ) ) )
78
+
79
+ assert_equal(2, @jar.cookies(url).length)
80
+
81
+ url2 = URI.parse('http://RuByFoRgE.oRg/')
82
+ assert_equal(2, @jar.cookies(url2).length)
83
+ end
84
+
85
+ def test_add_future_cookies
86
+ url = URI.parse('http://rubyforge.org/')
87
+
88
+ # Add one cookie with an expiration date in the future
89
+ cookie = cookie_from_hash(cookie_values)
90
+ @jar.add(url, cookie)
91
+ assert_equal(1, @jar.cookies(url).length)
92
+
93
+ # Add the same cookie, and we should still only have one
94
+ @jar.add(url, cookie_from_hash(cookie_values))
95
+ assert_equal(1, @jar.cookies(url).length)
96
+
97
+ # Make sure we can get the cookie from different paths
98
+ assert_equal(1, @jar.cookies(URI.parse('http://rubyforge.org/login')).length)
99
+
100
+ # Make sure we can't get the cookie from different domains
101
+ assert_equal(0, @jar.cookies(URI.parse('http://google.com/')).length)
102
+ end
103
+
104
+ def test_add_multiple_cookies
105
+ url = URI.parse('http://rubyforge.org/')
106
+
107
+ # Add one cookie with an expiration date in the future
108
+ cookie = cookie_from_hash(cookie_values)
109
+ @jar.add(url, cookie)
110
+ assert_equal(1, @jar.cookies(url).length)
111
+
112
+ # Add the same cookie, and we should still only have one
113
+ @jar.add(url, cookie_from_hash(cookie_values(:name => 'Baz')))
114
+ assert_equal(2, @jar.cookies(url).length)
115
+
116
+ # Make sure we can get the cookie from different paths
117
+ assert_equal(2, @jar.cookies(URI.parse('http://rubyforge.org/login')).length)
118
+
119
+ # Make sure we can't get the cookie from different domains
120
+ assert_equal(0, @jar.cookies(URI.parse('http://google.com/')).length)
121
+ end
122
+
123
+ def test_add_rejects_cookies_that_do_not_contain_an_embedded_dot
124
+ url = URI.parse('http://rubyforge.org/')
125
+
126
+ tld_cookie = cookie_from_hash(cookie_values(:domain => '.org'))
127
+ @jar.add(url, tld_cookie)
128
+ single_dot_cookie = cookie_from_hash(cookie_values(:domain => '.'))
129
+ @jar.add(url, single_dot_cookie)
130
+
131
+ assert_equal(0, @jar.cookies(url).length)
132
+ end
133
+
134
+ def test_add_makes_exception_for_local_tld
135
+ url = URI.parse('http://example.local')
136
+
137
+ tld_cookie = cookie_from_hash(cookie_values(:domain => '.local'))
138
+ @jar.add(url, tld_cookie)
139
+
140
+ assert_equal(1, @jar.cookies(url).length)
141
+ end
142
+
143
+ def test_add_makes_exception_for_localhost
144
+ url = URI.parse('http://localhost')
145
+
146
+ tld_cookie = cookie_from_hash(cookie_values(:domain => 'localhost'))
147
+ @jar.add(url, tld_cookie)
148
+
149
+ assert_equal(1, @jar.cookies(url).length)
150
+ end
151
+
152
+ def test_add_cookie_for_the_parent_domain
153
+ url = URI.parse('http://x.foo.com')
154
+
155
+ cookie = cookie_from_hash(cookie_values(:domain => '.foo.com'))
156
+ @jar.add(url, cookie)
157
+
158
+ assert_equal(1, @jar.cookies(url).length)
159
+ end
160
+
161
+ def test_add_rejects_cookies_from_a_nested_subdomain
162
+ url = URI.parse('http://y.x.foo.com')
163
+
164
+ cookie = cookie_from_hash(cookie_values(:domain => '.foo.com'))
165
+ @jar.add(url, cookie)
166
+
167
+ assert_equal(0, @jar.cookies(url).length)
168
+ end
169
+
170
+ def test_cookie_without_leading_dot_does_not_match_subdomains
171
+ url = URI.parse('http://admin.rubyforge.org/')
172
+
173
+ cookie = cookie_from_hash(cookie_values(:domain => 'rubyforge.org'))
174
+ @jar.add(url, cookie)
175
+
176
+ assert_equal(0, @jar.cookies(url).length)
177
+ end
178
+
179
+ def test_cookies_with_leading_dot_match_subdomains
180
+ url = URI.parse('http://admin.rubyforge.org/')
181
+
182
+ @jar.add(url, cookie_from_hash(cookie_values(:domain => '.rubyforge.org')))
183
+
184
+ assert_equal(1, @jar.cookies(url).length)
185
+ end
186
+
187
+ def test_cookies_dot
188
+ url = URI.parse('http://www.host.example/')
189
+
190
+ @jar.add(url,
191
+ cookie_from_hash(cookie_values(:domain => 'www.host.example')))
192
+
193
+ url = URI.parse('http://wwwxhost.example/')
194
+ assert_equal(0, @jar.cookies(url).length)
195
+ end
196
+
197
+ def test_clear_bang
198
+ url = URI.parse('http://rubyforge.org/')
199
+
200
+ # Add one cookie with an expiration date in the future
201
+ cookie = cookie_from_hash(cookie_values)
202
+ @jar.add(url, cookie)
203
+ @jar.add(url, cookie_from_hash(cookie_values(:name => 'Baz')))
204
+ assert_equal(2, @jar.cookies(url).length)
205
+
206
+ @jar.clear!
207
+
208
+ assert_equal(0, @jar.cookies(url).length)
209
+ end
210
+
211
+ def test_save_cookies_yaml
212
+ url = URI.parse('http://rubyforge.org/')
213
+
214
+ # Add one cookie with an expiration date in the future
215
+ cookie = cookie_from_hash(cookie_values)
216
+ s_cookie = cookie_from_hash(cookie_values(:name => 'Bar',
217
+ :expires => nil,
218
+ :session => true))
219
+
220
+ @jar.add(url, cookie)
221
+ @jar.add(url, s_cookie)
222
+ @jar.add(url, cookie_from_hash(cookie_values(:name => 'Baz')))
223
+
224
+ assert_equal(3, @jar.cookies(url).length)
225
+
226
+ @jar.save_as("cookies.yml")
227
+
228
+ jar = Mechanize::CookieJar.new
229
+ jar.load("cookies.yml")
230
+ assert_equal(2, jar.cookies(url).length)
231
+
232
+ assert_equal(3, @jar.cookies(url).length)
233
+ end
234
+
235
+ def test_save_cookies_cookiestxt
236
+ url = URI.parse('http://rubyforge.org/')
237
+
238
+ # Add one cookie with an expiration date in the future
239
+ cookie = cookie_from_hash(cookie_values)
240
+ s_cookie = cookie_from_hash(cookie_values(:name => 'Bar',
241
+ :expires => nil,
242
+ :session => true))
243
+
244
+ @jar.add(url, cookie)
245
+ @jar.add(url, s_cookie)
246
+ @jar.add(url, cookie_from_hash(cookie_values(:name => 'Baz')))
247
+
248
+ assert_equal(3, @jar.cookies(url).length)
249
+
250
+ @jar.save_as("cookies.txt", :cookiestxt)
251
+
252
+ jar = Mechanize::CookieJar.new
253
+ jar.load("cookies.txt", :cookiestxt) # HACK test the format
254
+ assert_equal(2, jar.cookies(url).length)
255
+
256
+ assert_equal(3, @jar.cookies(url).length)
257
+ end
258
+
259
+ def test_expire_cookies
260
+ url = URI.parse('http://rubyforge.org/')
261
+
262
+ # Add one cookie with an expiration date in the future
263
+ cookie = cookie_from_hash(cookie_values)
264
+ @jar.add(url, cookie)
265
+ assert_equal(1, @jar.cookies(url).length)
266
+
267
+ # Add a second cookie
268
+ @jar.add(url, cookie_from_hash(cookie_values(:name => 'Baz')))
269
+ assert_equal(2, @jar.cookies(url).length)
270
+
271
+ # Make sure we can get the cookie from different paths
272
+ assert_equal(2, @jar.cookies(URI.parse('http://rubyforge.org/login')).length)
273
+
274
+ # Expire the first cookie
275
+ @jar.add(url, cookie_from_hash(
276
+ cookie_values(:expires => Time.now - (10 * 86400))))
277
+ assert_equal(1, @jar.cookies(url).length)
278
+
279
+ # Expire the second cookie
280
+ @jar.add(url, cookie_from_hash(
281
+ cookie_values( :name => 'Baz', :expires => Time.now - (10 * 86400))))
282
+ assert_equal(0, @jar.cookies(url).length)
283
+ end
284
+
285
+ def test_session_cookies
286
+ values = cookie_values(:expires => nil)
287
+ url = URI.parse('http://rubyforge.org/')
288
+
289
+ # Add one cookie with an expiration date in the future
290
+ cookie = cookie_from_hash(values)
291
+ @jar.add(url, cookie)
292
+ assert_equal(1, @jar.cookies(url).length)
293
+
294
+ # Add a second cookie
295
+ @jar.add(url, cookie_from_hash(values.merge(:name => 'Baz')))
296
+ assert_equal(2, @jar.cookies(url).length)
297
+
298
+ # Make sure we can get the cookie from different paths
299
+ assert_equal(2, @jar.cookies(URI.parse('http://rubyforge.org/login')).length)
300
+
301
+ # Expire the first cookie
302
+ @jar.add(url, cookie_from_hash(values.merge(:expires => Time.now - (10 * 86400))))
303
+ assert_equal(1, @jar.cookies(url).length)
304
+
305
+ # Expire the second cookie
306
+ @jar.add(url, cookie_from_hash(
307
+ values.merge(:name => 'Baz', :expires => Time.now - (10 * 86400))))
308
+ assert_equal(0, @jar.cookies(url).length)
309
+
310
+ # When given a URI with a blank path, CookieJar#cookies should return
311
+ # cookies with the path '/':
312
+ url = URI.parse('http://rubyforge.org')
313
+ assert_equal '', url.path
314
+ assert_equal(0, @jar.cookies(url).length)
315
+ # Now add a cookie with the path set to '/':
316
+ @jar.add(url, cookie_from_hash(values.merge( :name => 'has_root_path',
317
+ :path => '/')))
318
+ assert_equal(1, @jar.cookies(url).length)
319
+ end
320
+
321
+ def test_paths
322
+ values = cookie_values(:path => "/login", :expires => nil)
323
+ url = URI.parse('http://rubyforge.org/login')
324
+
325
+ # Add one cookie with an expiration date in the future
326
+ cookie = cookie_from_hash(values)
327
+ @jar.add(url, cookie)
328
+ assert_equal(1, @jar.cookies(url).length)
329
+
330
+ # Add a second cookie
331
+ @jar.add(url, cookie_from_hash(values.merge( :name => 'Baz' )))
332
+ assert_equal(2, @jar.cookies(url).length)
333
+
334
+ # Make sure we don't get the cookie in a different path
335
+ assert_equal(0, @jar.cookies(URI.parse('http://rubyforge.org/hello')).length)
336
+ assert_equal(0, @jar.cookies(URI.parse('http://rubyforge.org/')).length)
337
+
338
+ # Expire the first cookie
339
+ @jar.add(url, cookie_from_hash(values.merge( :expires => Time.now - (10 * 86400))))
340
+ assert_equal(1, @jar.cookies(url).length)
341
+
342
+ # Expire the second cookie
343
+ @jar.add(url, cookie_from_hash(values.merge( :name => 'Baz',
344
+ :expires => Time.now - (10 * 86400))))
345
+ assert_equal(0, @jar.cookies(url).length)
346
+ end
347
+
348
+ def test_save_and_read_cookiestxt
349
+ url = URI.parse('http://rubyforge.org/')
350
+
351
+ # Add one cookie with an expiration date in the future
352
+ cookie = cookie_from_hash(cookie_values)
353
+ @jar.add(url, cookie)
354
+ @jar.add(url, cookie_from_hash(cookie_values(:name => 'Baz')))
355
+ assert_equal(2, @jar.cookies(url).length)
356
+
357
+ @jar.save_as("cookies.txt", :cookiestxt)
358
+ @jar.clear!
359
+
360
+ @jar.load("cookies.txt", :cookiestxt)
361
+ assert_equal(2, @jar.cookies(url).length)
362
+ end
363
+
364
+ def test_save_and_read_cookiestxt_with_session_cookies
365
+ url = URI.parse('http://rubyforge.org/')
366
+
367
+ @jar.add(url, cookie_from_hash(cookie_values(:expires => nil)))
368
+ @jar.save_as("cookies.txt", :cookiestxt)
369
+ @jar.clear!
370
+
371
+ @jar.load("cookies.txt", :cookiestxt)
372
+ assert_equal(1, @jar.cookies(url).length)
373
+ assert_nil @jar.cookies(url).first.expires
374
+ end
375
+
376
+ def test_save_and_read_expired_cookies
377
+ url = URI.parse('http://rubyforge.org/')
378
+
379
+ @jar.jar['rubyforge.org'] = {}
380
+
381
+
382
+ @jar.add url, cookie_from_hash(cookie_values)
383
+
384
+ # HACK no asertion
385
+ end
386
+
387
+ def test_ssl_cookies
388
+ # thanks to michal "ocher" ochman for reporting the bug responsible for this test.
389
+ values = cookie_values(:expires => nil)
390
+ values_ssl = values.merge(:domain => "#{values[:domain]}:443")
391
+ url = URI.parse('https://rubyforge.org/login')
392
+
393
+ cookie = cookie_from_hash(values)
394
+ @jar.add(url, cookie)
395
+ assert_equal(1, @jar.cookies(url).length, "did not handle SSL cookie")
396
+
397
+ cookie = cookie_from_hash(values_ssl)
398
+ @jar.add(url, cookie)
399
+ assert_equal(2, @jar.cookies(url).length, "did not handle SSL cookie with :443")
400
+ end
401
+ end