aai10-mechanize 2.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.
Files changed (176) hide show
  1. data/.autotest +6 -0
  2. data/.gitignore +9 -0
  3. data/CHANGELOG.rdoc +652 -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/aai10-mechanize.gemspec +20 -0
  12. data/examples/flickr_upload.rb +22 -0
  13. data/examples/mech-dump.rb +5 -0
  14. data/examples/proxy_req.rb +7 -0
  15. data/examples/rubyforge.rb +20 -0
  16. data/examples/spider.rb +21 -0
  17. data/lib/mechanize.rb +664 -0
  18. data/lib/mechanize/content_type_error.rb +14 -0
  19. data/lib/mechanize/cookie.rb +116 -0
  20. data/lib/mechanize/cookie_jar.rb +202 -0
  21. data/lib/mechanize/element_matcher.rb +35 -0
  22. data/lib/mechanize/file.rb +80 -0
  23. data/lib/mechanize/file_connection.rb +17 -0
  24. data/lib/mechanize/file_request.rb +26 -0
  25. data/lib/mechanize/file_response.rb +74 -0
  26. data/lib/mechanize/file_saver.rb +37 -0
  27. data/lib/mechanize/form.rb +478 -0
  28. data/lib/mechanize/form/button.rb +9 -0
  29. data/lib/mechanize/form/check_box.rb +11 -0
  30. data/lib/mechanize/form/field.rb +44 -0
  31. data/lib/mechanize/form/file_upload.rb +23 -0
  32. data/lib/mechanize/form/image_button.rb +20 -0
  33. data/lib/mechanize/form/multi_select_list.rb +83 -0
  34. data/lib/mechanize/form/option.rb +49 -0
  35. data/lib/mechanize/form/radio_button.rb +48 -0
  36. data/lib/mechanize/form/select_list.rb +40 -0
  37. data/lib/mechanize/headers.rb +25 -0
  38. data/lib/mechanize/history.rb +83 -0
  39. data/lib/mechanize/http.rb +3 -0
  40. data/lib/mechanize/http/agent.rb +738 -0
  41. data/lib/mechanize/inspect.rb +88 -0
  42. data/lib/mechanize/monkey_patch.rb +37 -0
  43. data/lib/mechanize/page.rb +408 -0
  44. data/lib/mechanize/page/base.rb +8 -0
  45. data/lib/mechanize/page/frame.rb +27 -0
  46. data/lib/mechanize/page/image.rb +30 -0
  47. data/lib/mechanize/page/label.rb +20 -0
  48. data/lib/mechanize/page/link.rb +82 -0
  49. data/lib/mechanize/page/meta_refresh.rb +56 -0
  50. data/lib/mechanize/pluggable_parsers.rb +101 -0
  51. data/lib/mechanize/redirect_limit_reached_error.rb +16 -0
  52. data/lib/mechanize/redirect_not_get_or_head_error.rb +19 -0
  53. data/lib/mechanize/response_code_error.rb +22 -0
  54. data/lib/mechanize/response_read_error.rb +27 -0
  55. data/lib/mechanize/robots_disallowed_error.rb +29 -0
  56. data/lib/mechanize/unsupported_scheme_error.rb +8 -0
  57. data/lib/mechanize/util.rb +113 -0
  58. data/test/data/htpasswd +1 -0
  59. data/test/data/server.crt +16 -0
  60. data/test/data/server.csr +12 -0
  61. data/test/data/server.key +15 -0
  62. data/test/data/server.pem +15 -0
  63. data/test/helper.rb +175 -0
  64. data/test/htdocs/alt_text.html +10 -0
  65. data/test/htdocs/bad_form_test.html +9 -0
  66. data/test/htdocs/button.jpg +0 -0
  67. data/test/htdocs/canonical_uri.html +9 -0
  68. data/test/htdocs/dir with spaces/foo.html +1 -0
  69. data/test/htdocs/empty_form.html +6 -0
  70. data/test/htdocs/file_upload.html +26 -0
  71. data/test/htdocs/find_link.html +41 -0
  72. data/test/htdocs/form_multi_select.html +16 -0
  73. data/test/htdocs/form_multival.html +37 -0
  74. data/test/htdocs/form_no_action.html +18 -0
  75. data/test/htdocs/form_no_input_name.html +16 -0
  76. data/test/htdocs/form_select.html +16 -0
  77. data/test/htdocs/form_select_all.html +16 -0
  78. data/test/htdocs/form_select_none.html +17 -0
  79. data/test/htdocs/form_select_noopts.html +10 -0
  80. data/test/htdocs/form_set_fields.html +14 -0
  81. data/test/htdocs/form_test.html +188 -0
  82. data/test/htdocs/frame_referer_test.html +10 -0
  83. data/test/htdocs/frame_test.html +30 -0
  84. data/test/htdocs/google.html +13 -0
  85. data/test/htdocs/iframe_test.html +16 -0
  86. data/test/htdocs/index.html +6 -0
  87. data/test/htdocs/link with space.html +5 -0
  88. data/test/htdocs/meta_cookie.html +11 -0
  89. data/test/htdocs/no_title_test.html +6 -0
  90. data/test/htdocs/nofollow.html +9 -0
  91. data/test/htdocs/noindex.html +9 -0
  92. data/test/htdocs/norobots.html +8 -0
  93. data/test/htdocs/rails_3_encoding_hack_form_test.html +27 -0
  94. data/test/htdocs/rel_nofollow.html +8 -0
  95. data/test/htdocs/relative/tc_relative_links.html +21 -0
  96. data/test/htdocs/robots.html +8 -0
  97. data/test/htdocs/robots.txt +2 -0
  98. data/test/htdocs/tc_bad_charset.html +9 -0
  99. data/test/htdocs/tc_bad_links.html +5 -0
  100. data/test/htdocs/tc_base_images.html +10 -0
  101. data/test/htdocs/tc_base_link.html +8 -0
  102. data/test/htdocs/tc_blank_form.html +11 -0
  103. data/test/htdocs/tc_charset.html +6 -0
  104. data/test/htdocs/tc_checkboxes.html +19 -0
  105. data/test/htdocs/tc_encoded_links.html +5 -0
  106. data/test/htdocs/tc_field_precedence.html +11 -0
  107. data/test/htdocs/tc_follow_meta.html +8 -0
  108. data/test/htdocs/tc_form_action.html +48 -0
  109. data/test/htdocs/tc_images.html +8 -0
  110. data/test/htdocs/tc_links.html +18 -0
  111. data/test/htdocs/tc_meta_in_body.html +9 -0
  112. data/test/htdocs/tc_no_attributes.html +16 -0
  113. data/test/htdocs/tc_pretty_print.html +17 -0
  114. data/test/htdocs/tc_radiobuttons.html +17 -0
  115. data/test/htdocs/tc_referer.html +16 -0
  116. data/test/htdocs/tc_relative_links.html +19 -0
  117. data/test/htdocs/tc_textarea.html +23 -0
  118. data/test/htdocs/test_bad_encoding.html +52 -0
  119. data/test/htdocs/test_click.html +11 -0
  120. data/test/htdocs/unusual______.html +5 -0
  121. data/test/servlets.rb +402 -0
  122. data/test/ssl_server.rb +48 -0
  123. data/test/test_cookies.rb +129 -0
  124. data/test/test_form_action.rb +52 -0
  125. data/test/test_form_as_hash.rb +59 -0
  126. data/test/test_form_button.rb +46 -0
  127. data/test/test_frames.rb +34 -0
  128. data/test/test_headers.rb +33 -0
  129. data/test/test_history.rb +118 -0
  130. data/test/test_history_added.rb +16 -0
  131. data/test/test_html_unscape_forms.rb +46 -0
  132. data/test/test_if_modified_since.rb +20 -0
  133. data/test/test_images.rb +19 -0
  134. data/test/test_mechanize.rb +852 -0
  135. data/test/test_mechanize_cookie.rb +345 -0
  136. data/test/test_mechanize_cookie_jar.rb +433 -0
  137. data/test/test_mechanize_file.rb +53 -0
  138. data/test/test_mechanize_file_request.rb +19 -0
  139. data/test/test_mechanize_file_response.rb +21 -0
  140. data/test/test_mechanize_form.rb +576 -0
  141. data/test/test_mechanize_form_check_box.rb +37 -0
  142. data/test/test_mechanize_form_encoding.rb +120 -0
  143. data/test/test_mechanize_form_field.rb +21 -0
  144. data/test/test_mechanize_form_image_button.rb +12 -0
  145. data/test/test_mechanize_form_textarea.rb +51 -0
  146. data/test/test_mechanize_http_agent.rb +697 -0
  147. data/test/test_mechanize_link.rb +84 -0
  148. data/test/test_mechanize_page_encoding.rb +147 -0
  149. data/test/test_mechanize_page_link.rb +382 -0
  150. data/test/test_mechanize_page_meta_refresh.rb +115 -0
  151. data/test/test_mechanize_redirect_not_get_or_head_error.rb +18 -0
  152. data/test/test_mechanize_subclass.rb +22 -0
  153. data/test/test_mechanize_util.rb +92 -0
  154. data/test/test_multi_select.rb +118 -0
  155. data/test/test_no_attributes.rb +13 -0
  156. data/test/test_option.rb +18 -0
  157. data/test/test_pluggable_parser.rb +136 -0
  158. data/test/test_post_form.rb +37 -0
  159. data/test/test_pretty_print.rb +22 -0
  160. data/test/test_radiobutton.rb +75 -0
  161. data/test/test_redirect_limit_reached.rb +39 -0
  162. data/test/test_redirect_ok.rb +25 -0
  163. data/test/test_referer.rb +81 -0
  164. data/test/test_relative_links.rb +40 -0
  165. data/test/test_request.rb +13 -0
  166. data/test/test_response_code.rb +53 -0
  167. data/test/test_robots.rb +72 -0
  168. data/test/test_save_file.rb +48 -0
  169. data/test/test_scheme.rb +48 -0
  170. data/test/test_select.rb +119 -0
  171. data/test/test_select_all.rb +15 -0
  172. data/test/test_select_none.rb +15 -0
  173. data/test/test_select_noopts.rb +18 -0
  174. data/test/test_set_fields.rb +44 -0
  175. data/test/test_ssl_server.rb +20 -0
  176. metadata +360 -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,433 @@
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_does_not_reject_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(1, @jar.cookies(url).length)
168
+ end
169
+
170
+ def test_cookie_without_leading_dot_matches_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(1, @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_with_leading_dot_match_parent_domains
188
+ url = URI.parse('http://rubyforge.org/')
189
+
190
+ @jar.add(url, cookie_from_hash(cookie_values(:domain => '.rubyforge.org')))
191
+
192
+ assert_equal(1, @jar.cookies(url).length)
193
+ end
194
+
195
+ def test_cookies_with_leading_dot_match_parent_domains_exactly
196
+ url = URI.parse('http://arubyforge.org/')
197
+
198
+ @jar.add(url, cookie_from_hash(cookie_values(:domain => '.rubyforge.org')))
199
+
200
+ assert_equal(0, @jar.cookies(url).length)
201
+ end
202
+
203
+ def test_cookies_dot
204
+ url = URI.parse('http://www.host.example/')
205
+
206
+ @jar.add(url,
207
+ cookie_from_hash(cookie_values(:domain => 'www.host.example')))
208
+
209
+ url = URI.parse('http://wwwxhost.example/')
210
+ assert_equal(0, @jar.cookies(url).length)
211
+ end
212
+
213
+ def test_clear_bang
214
+ url = URI.parse('http://rubyforge.org/')
215
+
216
+ # Add one cookie with an expiration date in the future
217
+ cookie = cookie_from_hash(cookie_values)
218
+ @jar.add(url, cookie)
219
+ @jar.add(url, cookie_from_hash(cookie_values(:name => 'Baz')))
220
+ assert_equal(2, @jar.cookies(url).length)
221
+
222
+ @jar.clear!
223
+
224
+ assert_equal(0, @jar.cookies(url).length)
225
+ end
226
+
227
+ def test_save_cookies_yaml
228
+ url = URI.parse('http://rubyforge.org/')
229
+
230
+ # Add one cookie with an expiration date in the future
231
+ cookie = cookie_from_hash(cookie_values)
232
+ s_cookie = cookie_from_hash(cookie_values(:name => 'Bar',
233
+ :expires => nil,
234
+ :session => true))
235
+
236
+ @jar.add(url, cookie)
237
+ @jar.add(url, s_cookie)
238
+ @jar.add(url, cookie_from_hash(cookie_values(:name => 'Baz')))
239
+
240
+ assert_equal(3, @jar.cookies(url).length)
241
+
242
+ @jar.save_as("cookies.yml")
243
+
244
+ jar = Mechanize::CookieJar.new
245
+ jar.load("cookies.yml")
246
+ assert_equal(2, jar.cookies(url).length)
247
+
248
+ assert_equal(3, @jar.cookies(url).length)
249
+ end
250
+
251
+ def test_save_cookies_cookiestxt
252
+ url = URI.parse('http://rubyforge.org/')
253
+
254
+ # Add one cookie with an expiration date in the future
255
+ cookie = cookie_from_hash(cookie_values)
256
+ s_cookie = cookie_from_hash(cookie_values(:name => 'Bar',
257
+ :expires => nil,
258
+ :session => true))
259
+
260
+ @jar.add(url, cookie)
261
+ @jar.add(url, s_cookie)
262
+ @jar.add(url, cookie_from_hash(cookie_values(:name => 'Baz')))
263
+
264
+ assert_equal(3, @jar.cookies(url).length)
265
+
266
+ @jar.save_as("cookies.txt", :cookiestxt)
267
+
268
+ jar = Mechanize::CookieJar.new
269
+ jar.load("cookies.txt", :cookiestxt) # HACK test the format
270
+ assert_equal(2, jar.cookies(url).length)
271
+
272
+ assert_equal(3, @jar.cookies(url).length)
273
+ end
274
+
275
+ def test_expire_cookies
276
+ url = URI.parse('http://rubyforge.org/')
277
+
278
+ # Add one cookie with an expiration date in the future
279
+ cookie = cookie_from_hash(cookie_values)
280
+ @jar.add(url, cookie)
281
+ assert_equal(1, @jar.cookies(url).length)
282
+
283
+ # Add a second cookie
284
+ @jar.add(url, cookie_from_hash(cookie_values(:name => 'Baz')))
285
+ assert_equal(2, @jar.cookies(url).length)
286
+
287
+ # Make sure we can get the cookie from different paths
288
+ assert_equal(2, @jar.cookies(URI.parse('http://rubyforge.org/login')).length)
289
+
290
+ # Expire the first cookie
291
+ @jar.add(url, cookie_from_hash(
292
+ cookie_values(:expires => Time.now - (10 * 86400))))
293
+ assert_equal(1, @jar.cookies(url).length)
294
+
295
+ # Expire the second cookie
296
+ @jar.add(url, cookie_from_hash(
297
+ cookie_values( :name => 'Baz', :expires => Time.now - (10 * 86400))))
298
+ assert_equal(0, @jar.cookies(url).length)
299
+ end
300
+
301
+ def test_session_cookies
302
+ values = cookie_values(:expires => nil)
303
+ url = URI.parse('http://rubyforge.org/')
304
+
305
+ # Add one cookie with an expiration date in the future
306
+ cookie = cookie_from_hash(values)
307
+ @jar.add(url, cookie)
308
+ assert_equal(1, @jar.cookies(url).length)
309
+
310
+ # Add a second cookie
311
+ @jar.add(url, cookie_from_hash(values.merge(:name => 'Baz')))
312
+ assert_equal(2, @jar.cookies(url).length)
313
+
314
+ # Make sure we can get the cookie from different paths
315
+ assert_equal(2, @jar.cookies(URI.parse('http://rubyforge.org/login')).length)
316
+
317
+ # Expire the first cookie
318
+ @jar.add(url, cookie_from_hash(values.merge(:expires => Time.now - (10 * 86400))))
319
+ assert_equal(1, @jar.cookies(url).length)
320
+
321
+ # Expire the second cookie
322
+ @jar.add(url, cookie_from_hash(
323
+ values.merge(:name => 'Baz', :expires => Time.now - (10 * 86400))))
324
+ assert_equal(0, @jar.cookies(url).length)
325
+
326
+ # When given a URI with a blank path, CookieJar#cookies should return
327
+ # cookies with the path '/':
328
+ url = URI.parse('http://rubyforge.org')
329
+ assert_equal '', url.path
330
+ assert_equal(0, @jar.cookies(url).length)
331
+ # Now add a cookie with the path set to '/':
332
+ @jar.add(url, cookie_from_hash(values.merge( :name => 'has_root_path',
333
+ :path => '/')))
334
+ assert_equal(1, @jar.cookies(url).length)
335
+ end
336
+
337
+ def test_paths
338
+ values = cookie_values(:path => "/login", :expires => nil)
339
+ url = URI.parse('http://rubyforge.org/login')
340
+
341
+ # Add one cookie with an expiration date in the future
342
+ cookie = cookie_from_hash(values)
343
+ @jar.add(url, cookie)
344
+ assert_equal(1, @jar.cookies(url).length)
345
+
346
+ # Add a second cookie
347
+ @jar.add(url, cookie_from_hash(values.merge( :name => 'Baz' )))
348
+ assert_equal(2, @jar.cookies(url).length)
349
+
350
+ # Make sure we don't get the cookie in a different path
351
+ assert_equal(0, @jar.cookies(URI.parse('http://rubyforge.org/hello')).length)
352
+ assert_equal(0, @jar.cookies(URI.parse('http://rubyforge.org/')).length)
353
+
354
+ # Expire the first cookie
355
+ @jar.add(url, cookie_from_hash(values.merge( :expires => Time.now - (10 * 86400))))
356
+ assert_equal(1, @jar.cookies(url).length)
357
+
358
+ # Expire the second cookie
359
+ @jar.add(url, cookie_from_hash(values.merge( :name => 'Baz',
360
+ :expires => Time.now - (10 * 86400))))
361
+ assert_equal(0, @jar.cookies(url).length)
362
+ end
363
+
364
+ def test_save_and_read_cookiestxt
365
+ url = URI.parse('http://rubyforge.org/')
366
+
367
+ # Add one cookie with an expiration date in the future
368
+ cookie = cookie_from_hash(cookie_values)
369
+ @jar.add(url, cookie)
370
+ @jar.add(url, cookie_from_hash(cookie_values(:name => 'Baz')))
371
+ assert_equal(2, @jar.cookies(url).length)
372
+
373
+ @jar.save_as("cookies.txt", :cookiestxt)
374
+ @jar.clear!
375
+
376
+ @jar.load("cookies.txt", :cookiestxt)
377
+ assert_equal(2, @jar.cookies(url).length)
378
+ end
379
+
380
+ def test_save_and_read_cookiestxt_with_session_cookies
381
+ url = URI.parse('http://rubyforge.org/')
382
+
383
+ @jar.add(url, cookie_from_hash(cookie_values(:expires => nil)))
384
+ @jar.save_as("cookies.txt", :cookiestxt)
385
+ @jar.clear!
386
+
387
+ @jar.load("cookies.txt", :cookiestxt)
388
+ assert_equal(1, @jar.cookies(url).length)
389
+ assert_nil @jar.cookies(url).first.expires
390
+ end
391
+
392
+ def test_save_and_read_expired_cookies
393
+ url = URI.parse('http://rubyforge.org/')
394
+
395
+ @jar.jar['rubyforge.org'] = {}
396
+
397
+
398
+ @jar.add url, cookie_from_hash(cookie_values)
399
+
400
+ # HACK no asertion
401
+ end
402
+
403
+ def test_ssl_cookies
404
+ # thanks to michal "ocher" ochman for reporting the bug responsible for this test.
405
+ values = cookie_values(:expires => nil)
406
+ values_ssl = values.merge(:name => 'Baz', :domain => "#{values[:domain]}:443")
407
+ url = URI.parse('https://rubyforge.org/login')
408
+
409
+ cookie = cookie_from_hash(values)
410
+ @jar.add(url, cookie)
411
+ assert_equal(1, @jar.cookies(url).length, "did not handle SSL cookie")
412
+
413
+ cookie = cookie_from_hash(values_ssl)
414
+ @jar.add(url, cookie)
415
+ assert_equal(2, @jar.cookies(url).length, "did not handle SSL cookie with :443")
416
+ end
417
+
418
+ def test_secure_cookie
419
+ nurl = URI.parse('http://rubyforge.org/login')
420
+ surl = URI.parse('https://rubyforge.org/login')
421
+
422
+ ncookie = cookie_from_hash(cookie_values(:name => 'Foo1'))
423
+ scookie = cookie_from_hash(cookie_values(:name => 'Foo2', :secure => true))
424
+
425
+ @jar.add(nurl, ncookie)
426
+ @jar.add(nurl, scookie)
427
+ @jar.add(surl, ncookie)
428
+ @jar.add(surl, scookie)
429
+
430
+ assert_equal('Foo1', @jar.cookies(nurl).map { |c| c.name }.sort.join(' ') )
431
+ assert_equal('Foo1 Foo2', @jar.cookies(surl).map { |c| c.name }.sort.join(' ') )
432
+ end
433
+ end